<!DOCTYPE html>
<html lang="en">
    <head hexo-theme='https://github.com/volantis-x/hexo-theme-volantis/#5.8.0'>
  <meta name="generator" content="Hexo 6.3.0">
  <meta name="Volantis" content="5.8.0">
  <meta charset="utf-8">
  <!-- SEO相关 -->
  
  <link rel="canonical" href="http://8.219.11.28/2024/02/23/前后端-springboot/"/>
  <!-- 渲染优化 -->
    <meta http-equiv='x-dns-prefetch-control' content='on' />
      <link rel='dns-prefetch' href='https://unpkg.com'>
      <link rel="preconnect" href="https://unpkg.com" crossorigin>
  <meta name="renderer" content="webkit">
  <meta name="force-rendering" content="webkit">
  <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
    <meta http-equiv="Content-Security-Policy" content=" default-src 'self' https:; block-all-mixed-content; base-uri 'self' https:; form-action 'self' https:; worker-src 'self' https:; connect-src 'self' https: *; img-src 'self' data: https: *; media-src 'self' https: *; font-src 'self' data: https: *; frame-src 'self' https: *; manifest-src 'self' https: *; child-src https:; script-src 'self' https: 'unsafe-inline' *; style-src 'self' https: 'unsafe-inline' *; ">
  <meta name="HandheldFriendly" content="True" >
  <meta name="apple-mobile-web-app-capable" content="yes">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=5">
  <meta content="black-translucent" name="apple-mobile-web-app-status-bar-style">
  <meta content="telephone=no" name="format-detection">
  <!-- import head_begin begin -->
  <!-- import head_begin end -->
  <!-- Custom Files headBegin begin-->
  
  <!-- Custom Files headBegin end-->
  <!-- front-matter head_begin begin -->
  <!-- front-matter head_begin end -->
  <link rel="preload" href="/css/style.css" as="style">
  <link rel="preload" href="https://unpkg.com/volantis-static@0.0.1654736714924/media/fonts/VarelaRound/VarelaRound-Regular.ttf" as="font" type="font/ttf" crossorigin="anonymous">
<link rel="preload" href="https://unpkg.com/volantis-static@0.0.1654736714924/media/fonts/UbuntuMono/UbuntuMono-Regular.ttf" as="font" type="font/ttf" crossorigin="anonymous">

  <!-- feed -->
  <!-- 页面元数据 -->
  <title>欢迎来到我的个人博客~</title>
  <meta name="keywords" content="null">
  <meta desc name="description" content="这些技术大部分是自己总结的，非官方 - 天明 - 欢迎来到我的个人博客~">
  
<meta property="og:type" content="article">
<meta property="og:title" content="欢迎来到我的个人博客~">
<meta property="og:url" content="http://8.219.11.28/2024/02/23/%E5%89%8D%E5%90%8E%E7%AB%AF-SpringBoot/index.html">
<meta property="og:site_name" content="欢迎来到我的个人博客~">
<meta property="og:description" content="SpringBoot基础创建springboot的流程:1.maven 项目123456&lt;!--    所有springboot项目都必须继承自 spring-boot-starter-parent --&gt;&lt;parent&gt;    &lt;groupId&gt;org.springframework.boot&lt;&#x2F;groupId&gt;    &lt;artifactId">
<meta property="og:locale" content="en_US">
<meta property="og:image" content="https://unpkg.com/volantis-static@0.0.1654736714924/media/org.volantis/blog/favicon/android-chrome-192x192.png">
<meta property="article:published_time" content="2024-02-23T14:27:45.483Z">
<meta property="article:modified_time" content="2024-02-17T04:39:33.886Z">
<meta property="article:author" content="天明">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://unpkg.com/volantis-static@0.0.1654736714924/media/org.volantis/blog/favicon/android-chrome-192x192.png">
  <style>
    /* 首屏样式 */
    #safearea {
  display: none;
}
:root {
  --color-site-body: #f4f4f4;
  --color-site-bg: #f4f4f4;
  --color-site-inner: #fff;
  --color-site-footer: #666;
  --color-card: #fff;
  --color-text: #444;
  --color-block: #f6f6f6;
  --color-inlinecode: #c74f00;
  --color-codeblock: #fff7ea;
  --color-h1: #3a3a3a;
  --color-h2: #3a3a3a;
  --color-h3: #333;
  --color-h4: #444;
  --color-h5: #555;
  --color-h6: #666;
  --color-p: #444;
  --color-list: #666;
  --color-list-hl: #30ad91;
  --color-meta: #888;
  --color-read-bkg: #e0d8c8;
  --color-read-post: #f8f1e2;
  --color-copyright-bkg: #f5f5f5;
}
* {
  box-sizing: border-box;
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  outline: none;
  margin: 0;
  padding: 0;
}
*::-webkit-scrollbar {
  height: 4px;
  width: 4px;
}
*::-webkit-scrollbar-track-piece {
  background: transparent;
}
*::-webkit-scrollbar-thumb {
  background: #3dd9b6;
  cursor: pointer;
  border-radius: 2px;
  -webkit-border-radius: 2px;
}
*::-webkit-scrollbar-thumb:hover {
  background: #ff5722;
}
html {
  color: var(--color-text);
  width: 100%;
  height: 100%;
  font-family: UbuntuMono, "Varela Round", "PingFang SC", "Microsoft YaHei", Helvetica, Arial, Menlo, Monaco, monospace, sans-serif;
  font-size: 16px;
}
html >::-webkit-scrollbar {
  height: 4px;
  width: 4px;
}
html >::-webkit-scrollbar-track-piece {
  background: transparent;
}
html >::-webkit-scrollbar-thumb {
  background: #54b5a0 linear-gradient(45deg, rgba(255,255,255,0.4) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.4) 50%, rgba(255,255,255,0.4) 75%, transparent 75%, transparent);
  cursor: pointer;
  border-radius: 2px;
  -webkit-border-radius: 2px;
}
html >::-webkit-scrollbar-thumb:hover {
  background: #54b5a0 linear-gradient(45deg, rgba(255,255,255,0.4) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.4) 50%, rgba(255,255,255,0.4) 75%, transparent 75%, transparent);
}
body {
  background-color: var(--color-site-body);
  text-rendering: optimizelegibility;
  -webkit-tap-highlight-color: rgba(0,0,0,0);
  line-height: 1.6;
  -webkit-text-size-adjust: 100%;
  -ms-text-size-adjust: 100%;
}
body.modal-active {
  overflow: hidden;
}
@media screen and (max-width: 680px) {
  body.modal-active {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
  }
}
a {
  color: #2092ec;
  cursor: pointer;
  text-decoration: none;
  transition: all 0.28s ease;
  -webkit-transition: all 0.28s ease;
  -khtml-transition: all 0.28s ease;
  -moz-transition: all 0.28s ease;
  -o-transition: all 0.28s ease;
  -ms-transition: all 0.28s ease;
}
a:hover {
  color: #ff5722;
}
a:active,
a:hover {
  outline: 0;
}
ul,
ol {
  padding-left: 0;
}
ul li,
ol li {
  list-style: none;
}
header {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: block;
}
img {
  border: 0;
  background: none;
  max-width: 100%;
}
svg:not(:root) {
  overflow: hidden;
}
hr {
  -moz-box-sizing: content-box;
  box-sizing: content-box;
  -webkit-box-sizing: content-box;
  -moz-box-sizing: content-box;
  height: 0;
  border: 0;
  border-radius: 1px;
  -webkit-border-radius: 1px;
  border-bottom: 1px solid rgba(68,68,68,0.1);
}
button,
input {
  color: inherit;
  font: inherit;
  margin: 0;
}
button {
  overflow: visible;
  text-transform: none;
  -webkit-appearance: button;
  cursor: pointer;
}
@supports (backdrop-filter: blur(20px)) {
  .blur {
    background: rgba(255,255,255,0.9) !important;
    backdrop-filter: saturate(200%) blur(20px);
  }
}
.shadow {
  box-shadow: 0 1px 2px 0px rgba(0,0,0,0.1);
  -webkit-box-shadow: 0 1px 2px 0px rgba(0,0,0,0.1);
}
.shadow.floatable {
  transition: all 0.28s ease;
  -webkit-transition: all 0.28s ease;
  -khtml-transition: all 0.28s ease;
  -moz-transition: all 0.28s ease;
  -o-transition: all 0.28s ease;
  -ms-transition: all 0.28s ease;
}
.shadow.floatable:hover {
  box-shadow: 0 2px 4px 0px rgba(0,0,0,0.1), 0 4px 8px 0px rgba(0,0,0,0.1), 0 8px 16px 0px rgba(0,0,0,0.1);
  -webkit-box-shadow: 0 2px 4px 0px rgba(0,0,0,0.1), 0 4px 8px 0px rgba(0,0,0,0.1), 0 8px 16px 0px rgba(0,0,0,0.1);
}
#l_cover {
  min-height: 64px;
}
.cover-wrapper {
  top: 0;
  left: 0;
  max-width: 100%;
  height: 100vh;
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: -ms-flexbox /* TWEENER - IE 10 */;
  display: -webkit-flex /* NEW - Chrome */;
  display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */;
  display: flex;
  flex-wrap: nowrap;
  -webkit-flex-wrap: nowrap;
  -khtml-flex-wrap: nowrap;
  -moz-flex-wrap: nowrap;
  -o-flex-wrap: nowrap;
  -ms-flex-wrap: nowrap;
  -webkit-box-direction: normal;
  -moz-box-direction: normal;
  -webkit-box-orient: vertical;
  -moz-box-orient: vertical;
  -webkit-flex-direction: column;
  -ms-flex-direction: column;
  flex-direction: column;
  align-items: center;
  align-self: center;
  align-content: center;
  color: var(--color-site-inner);
  padding: 0 16px;
  user-select: none;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  position: relative;
  overflow: hidden;
  margin-bottom: -100px;
}
.cover-wrapper .cover-bg {
  position: absolute;
  width: 100%;
  height: 100%;
  background-position: center;
  background-size: cover;
  -webkit-background-size: cover;
  -moz-background-size: cover;
}
.cover-wrapper .cover-bg.lazyload:not(.loaded) {
  opacity: 0;
  -webkit-opacity: 0;
  -moz-opacity: 0;
}
.cover-wrapper .cover-bg.lazyload.loaded {
  animation-delay: 0s;
  animation-duration: 0.5s;
  animation-fill-mode: forwards;
  animation-timing-function: ease-out;
  animation-name: fadeIn;
}
@-moz-keyframes fadeIn {
  0% {
    opacity: 0;
    -webkit-opacity: 0;
    -moz-opacity: 0;
    filter: blur(12px);
    transform: scale(1.02);
    -webkit-transform: scale(1.02);
    -khtml-transform: scale(1.02);
    -moz-transform: scale(1.02);
    -o-transform: scale(1.02);
    -ms-transform: scale(1.02);
  }
  100% {
    opacity: 1;
    -webkit-opacity: 1;
    -moz-opacity: 1;
  }
}
@-webkit-keyframes fadeIn {
  0% {
    opacity: 0;
    -webkit-opacity: 0;
    -moz-opacity: 0;
    filter: blur(12px);
    transform: scale(1.02);
    -webkit-transform: scale(1.02);
    -khtml-transform: scale(1.02);
    -moz-transform: scale(1.02);
    -o-transform: scale(1.02);
    -ms-transform: scale(1.02);
  }
  100% {
    opacity: 1;
    -webkit-opacity: 1;
    -moz-opacity: 1;
  }
}
@-o-keyframes fadeIn {
  0% {
    opacity: 0;
    -webkit-opacity: 0;
    -moz-opacity: 0;
    filter: blur(12px);
    transform: scale(1.02);
    -webkit-transform: scale(1.02);
    -khtml-transform: scale(1.02);
    -moz-transform: scale(1.02);
    -o-transform: scale(1.02);
    -ms-transform: scale(1.02);
  }
  100% {
    opacity: 1;
    -webkit-opacity: 1;
    -moz-opacity: 1;
  }
}
@keyframes fadeIn {
  0% {
    opacity: 0;
    -webkit-opacity: 0;
    -moz-opacity: 0;
    filter: blur(12px);
    transform: scale(1.02);
    -webkit-transform: scale(1.02);
    -khtml-transform: scale(1.02);
    -moz-transform: scale(1.02);
    -o-transform: scale(1.02);
    -ms-transform: scale(1.02);
  }
  100% {
    opacity: 1;
    -webkit-opacity: 1;
    -moz-opacity: 1;
  }
}
.cover-wrapper .cover-body {
  z-index: 1;
  position: relative;
  width: 100%;
  height: 100%;
}
.cover-wrapper#full {
  height: calc(100vh + 100px);
  padding-bottom: 100px;
}
.cover-wrapper#half {
  max-height: 640px;
  min-height: 400px;
  height: calc(36vh - 64px + 200px);
}
.cover-wrapper #scroll-down {
  width: 100%;
  height: 64px;
  position: absolute;
  bottom: 100px;
  text-align: center;
  cursor: pointer;
}
.cover-wrapper #scroll-down .scroll-down-effects {
  color: #fff;
  font-size: 24px;
  line-height: 64px;
  position: absolute;
  width: 24px;
  left: calc(50% - 12px);
  text-shadow: 0 1px 2px rgba(0,0,0,0.1);
  animation: scroll-down-effect 1.5s infinite;
  -webkit-animation: scroll-down-effect 1.5s infinite;
  -khtml-animation: scroll-down-effect 1.5s infinite;
  -moz-animation: scroll-down-effect 1.5s infinite;
  -o-animation: scroll-down-effect 1.5s infinite;
  -ms-animation: scroll-down-effect 1.5s infinite;
}
@-moz-keyframes scroll-down-effect {
  0% {
    top: 0;
    opacity: 1;
    -webkit-opacity: 1;
    -moz-opacity: 1;
  }
  50% {
    top: -16px;
    opacity: 0.4;
    -webkit-opacity: 0.4;
    -moz-opacity: 0.4;
  }
  100% {
    top: 0;
    opacity: 1;
    -webkit-opacity: 1;
    -moz-opacity: 1;
  }
}
@-webkit-keyframes scroll-down-effect {
  0% {
    top: 0;
    opacity: 1;
    -webkit-opacity: 1;
    -moz-opacity: 1;
  }
  50% {
    top: -16px;
    opacity: 0.4;
    -webkit-opacity: 0.4;
    -moz-opacity: 0.4;
  }
  100% {
    top: 0;
    opacity: 1;
    -webkit-opacity: 1;
    -moz-opacity: 1;
  }
}
@-o-keyframes scroll-down-effect {
  0% {
    top: 0;
    opacity: 1;
    -webkit-opacity: 1;
    -moz-opacity: 1;
  }
  50% {
    top: -16px;
    opacity: 0.4;
    -webkit-opacity: 0.4;
    -moz-opacity: 0.4;
  }
  100% {
    top: 0;
    opacity: 1;
    -webkit-opacity: 1;
    -moz-opacity: 1;
  }
}
@keyframes scroll-down-effect {
  0% {
    top: 0;
    opacity: 1;
    -webkit-opacity: 1;
    -moz-opacity: 1;
  }
  50% {
    top: -16px;
    opacity: 0.4;
    -webkit-opacity: 0.4;
    -moz-opacity: 0.4;
  }
  100% {
    top: 0;
    opacity: 1;
    -webkit-opacity: 1;
    -moz-opacity: 1;
  }
}
.cover-wrapper .cover-body {
  margin-top: 64px;
  margin-bottom: 100px;
}
.cover-wrapper .cover-body,
.cover-wrapper .cover-body .top,
.cover-wrapper .cover-body .bottom {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: -ms-flexbox /* TWEENER - IE 10 */;
  display: -webkit-flex /* NEW - Chrome */;
  display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */;
  display: flex;
  -webkit-box-direction: normal;
  -moz-box-direction: normal;
  -webkit-box-orient: vertical;
  -moz-box-orient: vertical;
  -webkit-flex-direction: column;
  -ms-flex-direction: column;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  -webkit-justify-content: center;
  -khtml-justify-content: center;
  -moz-justify-content: center;
  -o-justify-content: center;
  -ms-justify-content: center;
  max-width: 100%;
}
.cover-wrapper .cover-body .bottom {
  margin-top: 32px;
}
.cover-wrapper .cover-body .title {
  font-family: "Varela Round", "PingFang SC", "Microsoft YaHei", Helvetica, Arial, Helvetica, monospace;
  font-size: 3.125rem;
  line-height: 1.2;
  text-shadow: 0 1px 2px rgba(0,0,0,0.1);
}
.cover-wrapper .cover-body .subtitle {
  font-size: 20px;
}
.cover-wrapper .cover-body .logo {
  max-height: 120px;
  max-width: calc(100% - 4 * 16px);
}
@media screen and (min-height: 1024px) {
  .cover-wrapper .cover-body .title {
    font-size: 3rem;
  }
  .cover-wrapper .cover-body .subtitle {
    font-size: 1.05rem;
  }
  .cover-wrapper .cover-body .logo {
    max-height: 150px;
  }
}
.cover-wrapper .cover-body .m_search {
  position: relative;
  max-width: calc(100% - 16px);
  width: 320px;
  vertical-align: middle;
}
.cover-wrapper .cover-body .m_search .form {
  position: relative;
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: block;
  width: 100%;
}
.cover-wrapper .cover-body .m_search .icon,
.cover-wrapper .cover-body .m_search .input {
  transition: all 0.28s ease;
  -webkit-transition: all 0.28s ease;
  -khtml-transition: all 0.28s ease;
  -moz-transition: all 0.28s ease;
  -o-transition: all 0.28s ease;
  -ms-transition: all 0.28s ease;
}
.cover-wrapper .cover-body .m_search .icon {
  position: absolute;
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: block;
  line-height: 2.5rem;
  width: 32px;
  top: 0;
  left: 5px;
  color: rgba(68,68,68,0.75);
}
.cover-wrapper .cover-body .m_search .input {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: block;
  height: 2.5rem;
  width: 100%;
  box-shadow: none;
  -webkit-box-shadow: none;
  box-sizing: border-box;
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  font-size: 0.875rem;
  -webkit-appearance: none;
  padding-left: 36px;
  border-radius: 1.4rem;
  -webkit-border-radius: 1.4rem;
  background: rgba(255,255,255,0.6);
  backdrop-filter: blur(10px);
  border: none;
  color: var(--color-text);
}
@media screen and (max-width: 500px) {
  .cover-wrapper .cover-body .m_search .input {
    padding-left: 36px;
  }
}
.cover-wrapper .cover-body .m_search .input:hover {
  background: rgba(255,255,255,0.8);
}
.cover-wrapper .cover-body .m_search .input:focus {
  background: #fff;
}
.cover-wrapper .list-h {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: -ms-flexbox /* TWEENER - IE 10 */;
  display: -webkit-flex /* NEW - Chrome */;
  display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */;
  display: flex;
  -webkit-box-direction: normal;
  -moz-box-direction: normal;
  -webkit-box-orient: horizontal;
  -moz-box-orient: horizontal;
  -webkit-flex-direction: row;
  -ms-flex-direction: row;
  flex-direction: row;
  flex-wrap: wrap;
  -webkit-flex-wrap: wrap;
  -khtml-flex-wrap: wrap;
  -moz-flex-wrap: wrap;
  -o-flex-wrap: wrap;
  -ms-flex-wrap: wrap;
  align-items: stretch;
  border-radius: 4px;
  -webkit-border-radius: 4px;
  user-select: none;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
}
.cover-wrapper .list-h a {
  -webkit-box-flex: 1;
  -moz-box-flex: 1;
  -webkit-flex: 1 0;
  -ms-flex: 1 0;
  flex: 1 0;
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: -ms-flexbox /* TWEENER - IE 10 */;
  display: -webkit-flex /* NEW - Chrome */;
  display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */;
  display: flex;
  font-weight: 600;
}
.cover-wrapper .list-h a img {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: block;
  border-radius: 2px;
  -webkit-border-radius: 2px;
  margin: 4px;
  min-width: 40px;
  max-width: 44px;
}
@media screen and (max-width: 768px) {
  .cover-wrapper .list-h a img {
    min-width: 36px;
    max-width: 40px;
  }
}
@media screen and (max-width: 500px) {
  .cover-wrapper .list-h a img {
    margin: 2px 4px;
    min-width: 32px;
    max-width: 36px;
  }
}
@media screen and (max-width: 375px) {
  .cover-wrapper .list-h a img {
    min-width: 28px;
    max-width: 32px;
  }
}
.cover-wrapper {
  max-width: 100%;
}
.cover-wrapper.search .bottom .menu {
  margin-top: 16px;
}
.cover-wrapper.search .bottom .menu .list-h a {
  white-space: nowrap;
  -webkit-box-direction: normal;
  -moz-box-direction: normal;
  -webkit-box-orient: horizontal;
  -moz-box-orient: horizontal;
  -webkit-flex-direction: row;
  -ms-flex-direction: row;
  flex-direction: row;
  align-items: baseline;
  padding: 2px;
  margin: 4px;
  color: var(--color-site-inner);
  opacity: 0.75;
  -webkit-opacity: 0.75;
  -moz-opacity: 0.75;
  text-shadow: 0 1px 2px rgba(0,0,0,0.05);
  border-bottom: 2px solid transparent;
}
.cover-wrapper.search .bottom .menu .list-h a i {
  margin-right: 4px;
}
.cover-wrapper.search .bottom .menu .list-h a p {
  font-size: 0.9375rem;
}
.cover-wrapper.search .bottom .menu .list-h a:hover,
.cover-wrapper.search .bottom .menu .list-h a.active,
.cover-wrapper.search .bottom .menu .list-h a:active {
  opacity: 1;
  -webkit-opacity: 1;
  -moz-opacity: 1;
  border-bottom: 2px solid var(--color-site-inner);
}
.cover-wrapper.dock .menu,
.cover-wrapper.featured .menu,
.cover-wrapper.focus .menu {
  border-radius: 6px;
  -webkit-border-radius: 6px;
}
.cover-wrapper.dock .menu .list-h a,
.cover-wrapper.featured .menu .list-h a,
.cover-wrapper.focus .menu .list-h a {
  -webkit-box-direction: normal;
  -moz-box-direction: normal;
  -webkit-box-orient: vertical;
  -moz-box-orient: vertical;
  -webkit-flex-direction: column;
  -ms-flex-direction: column;
  flex-direction: column;
  align-items: center;
  padding: 12px;
  line-height: 24px;
  border-radius: 4px;
  -webkit-border-radius: 4px;
  border-bottom: none;
  text-align: center;
  align-content: flex-end;
  color: rgba(68,68,68,0.7);
  font-size: 1.5rem;
}
@media screen and (max-width: 500px) {
  .cover-wrapper.dock .menu .list-h a,
  .cover-wrapper.featured .menu .list-h a,
  .cover-wrapper.focus .menu .list-h a {
    padding: 12px 8px;
  }
}
.cover-wrapper.dock .menu .list-h a i,
.cover-wrapper.featured .menu .list-h a i,
.cover-wrapper.focus .menu .list-h a i {
  margin: 8px;
}
.cover-wrapper.dock .menu .list-h a p,
.cover-wrapper.featured .menu .list-h a p,
.cover-wrapper.focus .menu .list-h a p {
  font-size: 0.875rem;
}
.cover-wrapper.dock .menu .list-h a.active,
.cover-wrapper.featured .menu .list-h a.active,
.cover-wrapper.focus .menu .list-h a.active {
  background: var(--color-card);
  backdrop-filter: none;
}
.cover-wrapper.dock .menu .list-h a.active i,
.cover-wrapper.featured .menu .list-h a.active i,
.cover-wrapper.focus .menu .list-h a.active i,
.cover-wrapper.dock .menu .list-h a.active i+p,
.cover-wrapper.featured .menu .list-h a.active i+p,
.cover-wrapper.focus .menu .list-h a.active i+p {
  color: #3dd9b6;
}
.cover-wrapper.dock .menu .list-h a.active img+p,
.cover-wrapper.featured .menu .list-h a.active img+p,
.cover-wrapper.focus .menu .list-h a.active img+p {
  color: var(--color-text);
}
.cover-wrapper.dock .menu .list-h a:hover,
.cover-wrapper.featured .menu .list-h a:hover,
.cover-wrapper.focus .menu .list-h a:hover {
  background: var(--color-card);
}
.cover-wrapper.dock .top {
  margin-bottom: 48px;
}
.cover-wrapper.dock .menu {
  background: rgba(255,255,255,0.5);
  position: absolute;
  bottom: 0;
  max-width: 100%;
}
.cover-wrapper.dock .menu .list-h {
  flex-wrap: nowrap;
  -webkit-flex-wrap: nowrap;
  -khtml-flex-wrap: nowrap;
  -moz-flex-wrap: nowrap;
  -o-flex-wrap: nowrap;
  -ms-flex-wrap: nowrap;
  margin: 4px;
}
.cover-wrapper.dock .menu .list-h a+a {
  margin-left: 4px;
}
@media screen and (max-width: 500px) {
  .cover-wrapper.dock .menu .list-h {
    overflow-x: scroll;
  }
  .cover-wrapper.dock .menu .list-h::-webkit-scrollbar {
    height: 0;
    width: 0;
  }
  .cover-wrapper.dock .menu .list-h::-webkit-scrollbar-track-piece {
    background: transparent;
  }
  .cover-wrapper.dock .menu .list-h::-webkit-scrollbar-thumb {
    background: #3dd9b6;
    cursor: pointer;
    border-radius: 0;
    -webkit-border-radius: 0;
  }
  .cover-wrapper.dock .menu .list-h::-webkit-scrollbar-thumb:hover {
    background: #ff5722;
  }
}
@supports (backdrop-filter: blur(20px)) {
  .cover-wrapper.dock .menu {
    background: rgba(255,255,255,0.5);
    backdrop-filter: saturate(200%) blur(20px);
  }
}
@font-face {
  font-family: 'UbuntuMono';
  src: url("https://unpkg.com/volantis-static@0.0.1654736714924/media/fonts/UbuntuMono/UbuntuMono-Regular.ttf");
  font-weight: 'normal';
  font-style: 'normal';
  font-display: swap;
}
@font-face {
  font-family: 'Varela Round';
  src: url("https://unpkg.com/volantis-static@0.0.1654736714924/media/fonts/VarelaRound/VarelaRound-Regular.ttf");
  font-weight: 'normal';
  font-style: 'normal';
  font-display: swap;
}
.l_header {
  position: fixed;
  z-index: 1000;
  top: 0;
  width: 100%;
  height: 64px;
  background: var(--color-card);
  box-shadow: 0 1px 2px 0px rgba(0,0,0,0.1);
  -webkit-box-shadow: 0 1px 2px 0px rgba(0,0,0,0.1);
}
.l_header.auto {
  transition: opacity 0.4s ease;
  -webkit-transition: opacity 0.4s ease;
  -khtml-transition: opacity 0.4s ease;
  -moz-transition: opacity 0.4s ease;
  -o-transition: opacity 0.4s ease;
  -ms-transition: opacity 0.4s ease;
  visibility: hidden;
}
.l_header.auto.show {
  opacity: 1 !important;
  -webkit-opacity: 1 !important;
  -moz-opacity: 1 !important;
  visibility: visible;
}
.l_header .container {
  margin-left: 16px;
  margin-right: 16px;
}
.l_header #wrapper {
  height: 100%;
  user-select: none;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
}
.l_header #wrapper .nav-main,
.l_header #wrapper .nav-sub {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: -ms-flexbox /* TWEENER - IE 10 */;
  display: -webkit-flex /* NEW - Chrome */;
  display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */;
  display: flex;
  flex-wrap: nowrap;
  -webkit-flex-wrap: nowrap;
  -khtml-flex-wrap: nowrap;
  -moz-flex-wrap: nowrap;
  -o-flex-wrap: nowrap;
  -ms-flex-wrap: nowrap;
  justify-content: space-between;
  -webkit-justify-content: space-between;
  -khtml-justify-content: space-between;
  -moz-justify-content: space-between;
  -o-justify-content: space-between;
  -ms-justify-content: space-between;
  align-items: center;
}
.l_header #wrapper .nav-main {
  transition: all 0.28s ease;
  -webkit-transition: all 0.28s ease;
  -khtml-transition: all 0.28s ease;
  -moz-transition: all 0.28s ease;
  -o-transition: all 0.28s ease;
  -ms-transition: all 0.28s ease;
}
.l_header #wrapper.sub .nav-main {
  transform: translateY(-64px);
  -webkit-transform: translateY(-64px);
  -khtml-transform: translateY(-64px);
  -moz-transform: translateY(-64px);
  -o-transform: translateY(-64px);
  -ms-transform: translateY(-64px);
}
.l_header #wrapper .nav-sub {
  transition: all 0.28s ease;
  -webkit-transition: all 0.28s ease;
  -khtml-transition: all 0.28s ease;
  -moz-transition: all 0.28s ease;
  -o-transition: all 0.28s ease;
  -ms-transition: all 0.28s ease;
  opacity: 0;
  -webkit-opacity: 0;
  -moz-opacity: 0;
  height: 64px;
  width: calc(100% - 2 * 16px);
  position: absolute;
}
.l_header #wrapper .nav-sub ::-webkit-scrollbar {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: none;
}
@media screen and (min-width: 2048px) {
  .l_header #wrapper .nav-sub {
    max-width: 55vw;
    margin: auto;
  }
}
.l_header #wrapper.sub .nav-sub {
  opacity: 1;
  -webkit-opacity: 1;
  -moz-opacity: 1;
}
.l_header #wrapper .title {
  position: relative;
  color: var(--color-text);
  padding-left: 24px;
  max-height: 64px;
}
.l_header #wrapper .nav-main .title {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  flex-shrink: 0;
  line-height: 64px;
  padding: 0 24px;
  font-size: 1.25rem;
  font-family: "Varela Round", "PingFang SC", "Microsoft YaHei", Helvetica, Arial, Helvetica, monospace;
}
.l_header #wrapper .nav-main .title img {
  height: 64px;
}
.l_header .nav-sub {
  max-width: 1080px;
  margin: auto;
}
.l_header .nav-sub .title {
  font-weight: bold;
  font-family: UbuntuMono, "Varela Round", "PingFang SC", "Microsoft YaHei", Helvetica, Arial, Menlo, Monaco, monospace, sans-serif;
  line-height: 1.2;
  max-height: 64px;
  white-space: normal;
  flex-shrink: 1;
}
.l_header .switcher {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: none;
  line-height: 64px;
  align-items: center;
}
.l_header .switcher .s-toc {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: none;
}
@media screen and (max-width: 768px) {
  .l_header .switcher .s-toc {
    display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
    display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
    display: -ms-flexbox /* TWEENER - IE 10 */;
    display: -webkit-flex /* NEW - Chrome */;
    display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */;
    display: flex;
  }
}
.l_header .switcher >li {
  height: 48px;
  transition: all 0.28s ease;
  -webkit-transition: all 0.28s ease;
  -khtml-transition: all 0.28s ease;
  -moz-transition: all 0.28s ease;
  -o-transition: all 0.28s ease;
  -ms-transition: all 0.28s ease;
  margin: 2px;
}
@media screen and (max-width: 500px) {
  .l_header .switcher >li {
    margin: 0 1px;
    height: 48px;
  }
}
.l_header .switcher >li >a {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: -ms-flexbox /* TWEENER - IE 10 */;
  display: -webkit-flex /* NEW - Chrome */;
  display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */;
  display: flex;
  justify-content: center;
  -webkit-justify-content: center;
  -khtml-justify-content: center;
  -moz-justify-content: center;
  -o-justify-content: center;
  -ms-justify-content: center;
  align-items: center;
  width: 48px;
  height: 48px;
  padding: 0.85em 1.1em;
  border-radius: 100px;
  -webkit-border-radius: 100px;
  border: none;
  transition: all 0.28s ease;
  -webkit-transition: all 0.28s ease;
  -khtml-transition: all 0.28s ease;
  -moz-transition: all 0.28s ease;
  -o-transition: all 0.28s ease;
  -ms-transition: all 0.28s ease;
  color: #3dd9b6;
}
.l_header .switcher >li >a:hover {
  border: none;
}
.l_header .switcher >li >a.active,
.l_header .switcher >li >a:active {
  border: none;
  background: var(--color-site-bg);
}
@media screen and (max-width: 500px) {
  .l_header .switcher >li >a {
    width: 36px;
    height: 48px;
  }
}
.l_header .nav-sub .switcher {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: -ms-flexbox /* TWEENER - IE 10 */;
  display: -webkit-flex /* NEW - Chrome */;
  display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */;
  display: flex;
}
.l_header .m_search {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: -ms-flexbox /* TWEENER - IE 10 */;
  display: -webkit-flex /* NEW - Chrome */;
  display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */;
  display: flex;
  height: 64px;
  width: 240px;
  transition: all 0.28s ease;
  -webkit-transition: all 0.28s ease;
  -khtml-transition: all 0.28s ease;
  -moz-transition: all 0.28s ease;
  -o-transition: all 0.28s ease;
  -ms-transition: all 0.28s ease;
}
@media screen and (max-width: 1024px) {
  .l_header .m_search {
    width: 44px;
    min-width: 44px;
  }
  .l_header .m_search input::placeholder {
    opacity: 0;
    -webkit-opacity: 0;
    -moz-opacity: 0;
  }
  .l_header .m_search:hover {
    width: 240px;
  }
  .l_header .m_search:hover input::placeholder {
    opacity: 1;
    -webkit-opacity: 1;
    -moz-opacity: 1;
  }
}
@media screen and (min-width: 500px) {
  .l_header .m_search:hover .input {
    width: 100%;
  }
  .l_header .m_search:hover .input::placeholder {
    opacity: 1;
    -webkit-opacity: 1;
    -moz-opacity: 1;
  }
}
@media screen and (max-width: 500px) {
  .l_header .m_search {
    min-width: 0;
  }
  .l_header .m_search input::placeholder {
    opacity: 1;
    -webkit-opacity: 1;
    -moz-opacity: 1;
  }
}
.l_header .m_search .form {
  position: relative;
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: -ms-flexbox /* TWEENER - IE 10 */;
  display: -webkit-flex /* NEW - Chrome */;
  display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */;
  display: flex;
  width: 100%;
  align-items: center;
}
.l_header .m_search .icon {
  position: absolute;
  width: 36px;
  left: 5px;
  color: var(--color-meta);
}
@media screen and (max-width: 500px) {
  .l_header .m_search .icon {
    display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
    display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
    display: none;
  }
}
.l_header .m_search .input {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: block;
  padding-top: 8px;
  padding-bottom: 8px;
  line-height: 1.3;
  width: 100%;
  color: var(--color-text);
  background: #fafafa;
  box-shadow: none;
  -webkit-box-shadow: none;
  box-sizing: border-box;
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  padding-left: 40px;
  font-size: 0.875rem;
  border-radius: 8px;
  -webkit-border-radius: 8px;
  border: none;
  transition: all 0.28s ease;
  -webkit-transition: all 0.28s ease;
  -khtml-transition: all 0.28s ease;
  -moz-transition: all 0.28s ease;
  -o-transition: all 0.28s ease;
  -ms-transition: all 0.28s ease;
}
@media screen and (min-width: 500px) {
  .l_header .m_search .input:focus {
    box-shadow: 0 4px 8px 0px rgba(0,0,0,0.1);
    -webkit-box-shadow: 0 4px 8px 0px rgba(0,0,0,0.1);
  }
}
@media screen and (max-width: 500px) {
  .l_header .m_search .input {
    background: var(--color-block);
    padding-left: 8px;
    border: none;
  }
  .l_header .m_search .input:hover,
  .l_header .m_search .input:focus {
    border: none;
  }
}
@media (max-width: 500px) {
  .l_header .m_search {
    left: 0;
    width: 0;
    overflow: hidden;
    position: absolute;
    background: #fff;
    transition: all 0.28s ease;
    -webkit-transition: all 0.28s ease;
    -khtml-transition: all 0.28s ease;
    -moz-transition: all 0.28s ease;
    -o-transition: all 0.28s ease;
    -ms-transition: all 0.28s ease;
  }
  .l_header .m_search .input {
    border-radius: 32px;
    -webkit-border-radius: 32px;
    margin-left: 16px;
    padding-left: 16px;
  }
  .l_header.z_search-open .m_search {
    width: 100%;
  }
  .l_header.z_search-open .m_search .input {
    width: calc(100% - 120px);
  }
}
ul.m-pc >li>a {
  color: inherit;
  border-bottom: 2px solid transparent;
}
ul.m-pc >li>a:active,
ul.m-pc >li>a.active {
  border-bottom: 2px solid #3dd9b6;
}
ul.m-pc li:hover >ul.list-v,
ul.list-v li:hover >ul.list-v {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: block;
}
ul.nav-list-h {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: -ms-flexbox /* TWEENER - IE 10 */;
  display: -webkit-flex /* NEW - Chrome */;
  display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */;
  display: flex;
  align-items: stretch;
}
ul.nav-list-h>li {
  position: relative;
  justify-content: center;
  -webkit-justify-content: center;
  -khtml-justify-content: center;
  -moz-justify-content: center;
  -o-justify-content: center;
  -ms-justify-content: center;
  height: 100%;
  line-height: 2.4;
  border-radius: 4px;
  -webkit-border-radius: 4px;
}
ul.nav-list-h>li >a {
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-weight: 600;
}
ul.list-v {
  z-index: 1;
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: none;
  position: absolute;
  background: var(--color-card);
  box-shadow: 0 2px 4px 0px rgba(0,0,0,0.08), 0 4px 8px 0px rgba(0,0,0,0.08), 0 8px 16px 0px rgba(0,0,0,0.08);
  -webkit-box-shadow: 0 2px 4px 0px rgba(0,0,0,0.08), 0 4px 8px 0px rgba(0,0,0,0.08), 0 8px 16px 0px rgba(0,0,0,0.08);
  margin-top: -6px;
  border-radius: 4px;
  -webkit-border-radius: 4px;
  padding: 8px 0;
}
ul.list-v.show {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: block;
}
ul.list-v hr {
  margin-top: 8px;
  margin-bottom: 8px;
}
ul.list-v >li {
  white-space: nowrap;
  word-break: keep-all;
}
ul.list-v >li.header {
  font-size: 0.78125rem;
  font-weight: bold;
  line-height: 2em;
  color: var(--color-meta);
  margin: 8px 16px 4px;
}
ul.list-v >li.header i {
  margin-right: 8px;
}
ul.list-v >li ul {
  margin-left: 0;
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: none;
  margin-top: -40px;
}
ul.list-v .aplayer-container {
  min-height: 64px;
  padding: 6px 16px;
}
ul.list-v >li>a {
  transition: all 0.28s ease;
  -webkit-transition: all 0.28s ease;
  -khtml-transition: all 0.28s ease;
  -moz-transition: all 0.28s ease;
  -o-transition: all 0.28s ease;
  -ms-transition: all 0.28s ease;
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: block;
  color: var(--color-list);
  font-size: 0.875rem;
  font-weight: bold;
  line-height: 36px;
  padding: 0 20px 0 16px;
  text-overflow: ellipsis;
  margin: 0 4px;
  border-radius: 4px;
  -webkit-border-radius: 4px;
}
@media screen and (max-width: 1024px) {
  ul.list-v >li>a {
    line-height: 40px;
  }
}
ul.list-v >li>a >i {
  margin-right: 8px;
}
ul.list-v >li>a:active,
ul.list-v >li>a.active {
  color: var(--color-list-hl);
}
ul.list-v >li>a:hover {
  color: var(--color-list-hl);
  background: var(--color-site-bg);
}
.l_header .menu >ul>li>a {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: block;
  padding: 0 8px;
}
.l_header .menu >ul>li>a >i {
  margin-right: 4px;
}
.l_header ul.nav-list-h>li {
  color: var(--color-list);
  line-height: 64px;
}
.l_header ul.nav-list-h>li >a {
  max-height: 64px;
  overflow: hidden;
  color: inherit;
}
.l_header ul.nav-list-h>li >a:active,
.l_header ul.nav-list-h>li >a.active {
  color: #3dd9b6;
}
.l_header ul.nav-list-h>li:hover>a {
  color: var(--color-list-hl);
}
.l_header ul.nav-list-h>li i.music {
  animation: rotate-effect 1.5s linear infinite;
  -webkit-animation: rotate-effect 1.5s linear infinite;
  -khtml-animation: rotate-effect 1.5s linear infinite;
  -moz-animation: rotate-effect 1.5s linear infinite;
  -o-animation: rotate-effect 1.5s linear infinite;
  -ms-animation: rotate-effect 1.5s linear infinite;
}
@-moz-keyframes rotate-effect {
  0% {
    transform: rotate(0);
    -webkit-transform: rotate(0);
    -khtml-transform: rotate(0);
    -moz-transform: rotate(0);
    -o-transform: rotate(0);
    -ms-transform: rotate(0);
  }
  25% {
    transform: rotate(90deg);
    -webkit-transform: rotate(90deg);
    -khtml-transform: rotate(90deg);
    -moz-transform: rotate(90deg);
    -o-transform: rotate(90deg);
    -ms-transform: rotate(90deg);
  }
  50% {
    transform: rotate(180deg);
    -webkit-transform: rotate(180deg);
    -khtml-transform: rotate(180deg);
    -moz-transform: rotate(180deg);
    -o-transform: rotate(180deg);
    -ms-transform: rotate(180deg);
  }
  75% {
    transform: rotate(270deg);
    -webkit-transform: rotate(270deg);
    -khtml-transform: rotate(270deg);
    -moz-transform: rotate(270deg);
    -o-transform: rotate(270deg);
    -ms-transform: rotate(270deg);
  }
  100% {
    transform: rotate(360deg);
    -webkit-transform: rotate(360deg);
    -khtml-transform: rotate(360deg);
    -moz-transform: rotate(360deg);
    -o-transform: rotate(360deg);
    -ms-transform: rotate(360deg);
  }
}
@-webkit-keyframes rotate-effect {
  0% {
    transform: rotate(0);
    -webkit-transform: rotate(0);
    -khtml-transform: rotate(0);
    -moz-transform: rotate(0);
    -o-transform: rotate(0);
    -ms-transform: rotate(0);
  }
  25% {
    transform: rotate(90deg);
    -webkit-transform: rotate(90deg);
    -khtml-transform: rotate(90deg);
    -moz-transform: rotate(90deg);
    -o-transform: rotate(90deg);
    -ms-transform: rotate(90deg);
  }
  50% {
    transform: rotate(180deg);
    -webkit-transform: rotate(180deg);
    -khtml-transform: rotate(180deg);
    -moz-transform: rotate(180deg);
    -o-transform: rotate(180deg);
    -ms-transform: rotate(180deg);
  }
  75% {
    transform: rotate(270deg);
    -webkit-transform: rotate(270deg);
    -khtml-transform: rotate(270deg);
    -moz-transform: rotate(270deg);
    -o-transform: rotate(270deg);
    -ms-transform: rotate(270deg);
  }
  100% {
    transform: rotate(360deg);
    -webkit-transform: rotate(360deg);
    -khtml-transform: rotate(360deg);
    -moz-transform: rotate(360deg);
    -o-transform: rotate(360deg);
    -ms-transform: rotate(360deg);
  }
}
@-o-keyframes rotate-effect {
  0% {
    transform: rotate(0);
    -webkit-transform: rotate(0);
    -khtml-transform: rotate(0);
    -moz-transform: rotate(0);
    -o-transform: rotate(0);
    -ms-transform: rotate(0);
  }
  25% {
    transform: rotate(90deg);
    -webkit-transform: rotate(90deg);
    -khtml-transform: rotate(90deg);
    -moz-transform: rotate(90deg);
    -o-transform: rotate(90deg);
    -ms-transform: rotate(90deg);
  }
  50% {
    transform: rotate(180deg);
    -webkit-transform: rotate(180deg);
    -khtml-transform: rotate(180deg);
    -moz-transform: rotate(180deg);
    -o-transform: rotate(180deg);
    -ms-transform: rotate(180deg);
  }
  75% {
    transform: rotate(270deg);
    -webkit-transform: rotate(270deg);
    -khtml-transform: rotate(270deg);
    -moz-transform: rotate(270deg);
    -o-transform: rotate(270deg);
    -ms-transform: rotate(270deg);
  }
  100% {
    transform: rotate(360deg);
    -webkit-transform: rotate(360deg);
    -khtml-transform: rotate(360deg);
    -moz-transform: rotate(360deg);
    -o-transform: rotate(360deg);
    -ms-transform: rotate(360deg);
  }
}
@keyframes rotate-effect {
  0% {
    transform: rotate(0);
    -webkit-transform: rotate(0);
    -khtml-transform: rotate(0);
    -moz-transform: rotate(0);
    -o-transform: rotate(0);
    -ms-transform: rotate(0);
  }
  25% {
    transform: rotate(90deg);
    -webkit-transform: rotate(90deg);
    -khtml-transform: rotate(90deg);
    -moz-transform: rotate(90deg);
    -o-transform: rotate(90deg);
    -ms-transform: rotate(90deg);
  }
  50% {
    transform: rotate(180deg);
    -webkit-transform: rotate(180deg);
    -khtml-transform: rotate(180deg);
    -moz-transform: rotate(180deg);
    -o-transform: rotate(180deg);
    -ms-transform: rotate(180deg);
  }
  75% {
    transform: rotate(270deg);
    -webkit-transform: rotate(270deg);
    -khtml-transform: rotate(270deg);
    -moz-transform: rotate(270deg);
    -o-transform: rotate(270deg);
    -ms-transform: rotate(270deg);
  }
  100% {
    transform: rotate(360deg);
    -webkit-transform: rotate(360deg);
    -khtml-transform: rotate(360deg);
    -moz-transform: rotate(360deg);
    -o-transform: rotate(360deg);
    -ms-transform: rotate(360deg);
  }
}
.menu-phone li ul.list-v {
  right: calc(100% - 0.5 * 16px);
}
.menu-phone li ul.list-v ul {
  right: calc(100% - 0.5 * 16px);
}
#wrapper {
  max-width: 1080px;
  margin: auto;
}
@media screen and (min-width: 2048px) {
  #wrapper {
    max-width: 55vw;
  }
}
#wrapper .menu {
  -webkit-box-flex: 1;
  -moz-box-flex: 1;
  -webkit-flex: 1 1;
  -ms-flex: 1 1;
  flex: 1 1;
  margin: 0 16px 0 0;
}
#wrapper .menu .list-v ul {
  left: calc(100% - 0.5 * 16px);
}
.menu-phone {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: none;
  margin-top: 16px;
  right: 8px;
  transition: all 0.28s ease;
  -webkit-transition: all 0.28s ease;
  -khtml-transition: all 0.28s ease;
  -moz-transition: all 0.28s ease;
  -o-transition: all 0.28s ease;
  -ms-transition: all 0.28s ease;
}
.menu-phone ul {
  right: calc(100% - 0.5 * 16px);
}
@media screen and (max-width: 500px) {
  .menu-phone {
    display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
    display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
    display: block;
  }
}
.l_header {
  max-width: 65vw;
  left: calc((100% - 65vw) * 0.5);
  border-bottom-left-radius: 8px;
  border-bottom-right-radius: 8px;
}
@media screen and (max-width: 2048px) {
  .l_header {
    max-width: 1112px;
    left: calc((100% - 1112px) * 0.5);
  }
}
@media screen and (max-width: 1112px) {
  .l_header {
    left: 0;
    border-radius: 0;
    -webkit-border-radius: 0;
    max-width: 100%;
  }
}
@media screen and (max-width: 500px) {
  .l_header .container {
    margin-left: 0;
    margin-right: 0;
  }
  .l_header #wrapper .nav-main .title {
    padding-left: 16px;
    padding-right: 16px;
  }
  .l_header #wrapper .nav-sub {
    width: 100%;
  }
  .l_header #wrapper .nav-sub .title {
    overflow-y: scroll;
    margin-top: 2px;
    padding: 8px 16px;
  }
  .l_header #wrapper .switcher {
    display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
    display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
    display: -ms-flexbox /* TWEENER - IE 10 */;
    display: -webkit-flex /* NEW - Chrome */;
    display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */;
    display: flex;
    margin-right: 8px;
  }
  .l_header .menu {
    display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
    display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
    display: none;
  }
}
@media screen and (max-width: 500px) {
  .list-v li {
    max-width: 270px;
  }
}
#u-search {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: none;
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  padding: 60px 20px;
  z-index: 1001;
}
@media screen and (max-width: 680px) {
  #u-search {
    padding: 0px;
  }
}

  </style>
  <link rel="stylesheet" href="/css/style.css" media="print" onload="this.media='all';this.onload=null">
  <noscript><link rel="stylesheet" href="/css/style.css"></noscript>
  
<script>
if (/*@cc_on!@*/false || (!!window.MSInputMethodContext && !!document.documentMode))
    document.write(
	'<style>'+
		'html{'+
			'overflow-x: hidden !important;'+
			'overflow-y: hidden !important;'+
		'}'+
		'.kill-ie{'+
			'text-align:center;'+
			'height: 100%;'+
			'margin-top: 15%;'+
			'margin-bottom: 5500%;'+
		'}'+
    '.kill-t{'+
      'font-size: 2rem;'+
    '}'+
    '.kill-c{'+
      'font-size: 1.2rem;'+
    '}'+
		'#l_header,#l_body{'+
			'display: none;'+
		'}'+
	'</style>'+
    '<div class="kill-ie">'+
        `<span class="kill-t"><b>Sorry, your browser cannot access this site</b></span><br/>`+
        `<span class="kill-c">Microsoft has terminated support for Internet Explorer (IE) 10 and earlier versions in 2016. <br/>There are great security risks to continue using it. Please use contemporary mainstream browsers to access.</span><br/>`+
        `<a target="_blank" rel="noopener" href="https://blogs.windows.com/windowsexperience/2021/05/19/the-future-of-internet-explorer-on-windows-10-is-in-microsoft-edge/"><strong>Learn more ></strong></a>`+
    '</div>');
</script>


<noscript>
	<style>
		html{
			overflow-x: hidden !important;
			overflow-y: hidden !important;
		}
		.kill-noscript{
			text-align:center;
			height: 100%;
			margin-top: 15%;
			margin-bottom: 5500%;
		}
    .kill-t{
      font-size: 2rem;
    }
    .kill-c{
      font-size: 1.2rem;
    }
		#l_header,#l_body{
			display: none;
		}
	</style>
    <div class="kill-noscript">
        <span class="kill-t"><b>Sorry, your browser cannot access this site</b></span><br/>
        <span class="kill-c">This page requires browser support (enable) JavaScript</span><br/>
        <a target="_blank" rel="noopener" href="https://www.baidu.com/s?wd=启用JavaScript"><strong>Learn more ></strong></a>
    </div>
</noscript>


  <script>
  /************这个文件存放不需要重载的全局变量和全局函数*********/
  window.volantis = {}; // volantis 全局变量
  volantis.debug = "env"; // 调试模式
  volantis.dom = {}; // 页面Dom see: /source/js/app.js etc.

  volantis.GLOBAL_CONFIG ={
    debug: "env",
    cdn: {"js":{"app":"/js/app.js","parallax":"/js/plugins/parallax.js","rightMenu":"/js/plugins/rightMenu.js","rightMenus":"/js/plugins/rightMenus.js","sites":"/js/plugins/tags/sites.js","friends":"/js/plugins/tags/friends.js","contributors":"/js/plugins/tags/contributors.js","search":"/js/search/hexo.js"},"css":{"style":"/css/style.css"}},
    default: {"avatar":"https://unpkg.com/volantis-static@0.0.1654736714924/media/placeholder/avatar/round/3442075.svg","link":"https://unpkg.com/volantis-static@0.0.1654736714924/media/placeholder/link/8f277b4ee0ecd.svg","cover":"https://unpkg.com/volantis-static@0.0.1654736714924/media/placeholder/cover/76b86c0226ffd.svg","image":"https://unpkg.com/volantis-static@0.0.1654736714924/media/placeholder/image/2659360.svg"},
    lastupdate: new Date(1708699590610),
    sidebar: {
      for_page: ["blogger","category","tagcloud","donate"],
      for_post: ["toc"],
      webinfo: {
        lastupd: {
          enable: true,
          friendlyShow: true
        },
        runtime: {
          data: "2020/01/01",
          unit: "天"
        }
      }
    },
    plugins: {
      message: {"enable":true,"css":"https://unpkg.com/volantis-static@0.0.1654736714924/libs/izitoast/dist/css/iziToast.min.css","js":"https://unpkg.com/volantis-static@0.0.1654736714924/libs/izitoast/dist/js/iziToast.min.js","icon":{"default":"fa-solid fa-info-circle light-blue","quection":"fa-solid fa-question-circle light-blue"},"time":{"default":5000,"quection":20000},"position":"topRight","transitionIn":"bounceInLeft","transitionOut":"fadeOutRight","titleColor":"var(--color-text)","messageColor":"var(--color-text)","backgroundColor":"var(--color-card)","zindex":2147483647,"copyright":{"enable":true,"title":"知识共享许可协议","message":"请遵守 CC BY-NC-SA 4.0 协议。","icon":"far fa-copyright light-blue"},"aplayer":{"enable":true,"play":"fa-solid fa-play","pause":"fa-solid fa-pause"},"rightmenu":{"enable":true,"notice":true}},
      fancybox: {"css":"https://unpkg.com/volantis-static@0.0.1654736714924/libs/@fancyapps/ui/dist/fancybox.css","js":"https://unpkg.com/volantis-static@0.0.1654736714924/libs/@fancyapps/ui/dist/fancybox.umd.js"},
      
      
      
    }
  }

  /******************** volantis.EventListener ********************************/
  // 事件监听器 see: /source/js/app.js
  volantis.EventListener = {}
  // 这里存放pjax切换页面时将被移除的事件监听器
  volantis.EventListener.list = []
  //构造方法
  function volantisEventListener(type, f, ele) {
    this.type = type
    this.f = f
    this.ele = ele
  }
  // 移除事件监听器
  volantis.EventListener.remove = () => {
    volantis.EventListener.list.forEach(function (i) {
      i.ele.removeEventListener(i.type, i.f, false)
    })
    volantis.EventListener.list = []
  }
  /******************** volantis.dom.$ ********************************/
  // 注：这里没有选择器，也没有forEach一次只处理一个dom，这里重新封装主题常用的dom方法，返回的是dom对象，对象包含了以下方法，同时保留dom的原生API
  function volantisDom(ele) {
    if (!ele) ele = document.createElement("div")
    this.ele = ele;
    // ==============================================================
    this.ele.find = (c) => {
      let q = this.ele.querySelector(c)
      if (q)
        return new volantisDom(q)
    }
    // ==============================================================
    this.ele.hasClass = (c) => {
      return this.ele.className.match(new RegExp('(\\s|^)' + c + '(\\s|$)'));
    }
    this.ele.addClass = (c) => {
      this.ele.classList.add(c);
      return this.ele
    }
    this.ele.removeClass = (c) => {
      this.ele.classList.remove(c);
      return this.ele
    }
    this.ele.toggleClass = (c) => {
      if (this.ele.hasClass(c)) {
        this.ele.removeClass(c)
      } else {
        this.ele.addClass(c)
      }
      return this.ele
    }
    // ==============================================================
    // 参数 r 为 true 表示pjax切换页面时事件监听器将被移除，false不移除
    this.ele.on = (c, f, r = 1) => {
      this.ele.addEventListener(c, f, false)
      if (r) {
        volantis.EventListener.list.push(new volantisEventListener(c, f, this.ele))
      }
      return this.ele
    }
    this.ele.click = (f, r) => {
      this.ele.on("click", f, r)
      return this.ele
    }
    this.ele.scroll = (f, r) => {
      this.ele.on("scroll", f, r)
      return this.ele
    }
    // ==============================================================
    this.ele.html = (c) => {
      // if(c=== undefined){
      //   return this.ele.innerHTML
      // }else{
      this.ele.innerHTML = c
      return this.ele
      // }
    }
    // ==============================================================
    this.ele.hide = (c) => {
      this.ele.style.display = "none"
      return this.ele
    }
    this.ele.show = (c) => {
      this.ele.style.display = "block"
      return this.ele
    }
    // ==============================================================
    return this.ele
  }
  volantis.dom.$ = (ele) => {
    return !!ele ? new volantisDom(ele) : null;
  }
  /******************** RunItem ********************************/
  function RunItem() {
    this.list = []; // 存放回调函数
    this.start = () => {
      for (var i = 0; i < this.list.length; i++) {
        this.list[i].run();
      }
    };
    this.push = (fn, name, setRequestAnimationFrame = true) => {
      let myfn = fn
      if (setRequestAnimationFrame) {
        myfn = ()=>{
          volantis.requestAnimationFrame(fn)
        }
      }
      var f = new Item(myfn, name);
      this.list.push(f);
    };
    this.remove = (name) =>{
      for (let index = 0; index < this.list.length; index++) {
        const e = this.list[index];
        if (e.name == name) {
          this.list.splice(index,1);
        }
      }
    }
    // 构造一个可以run的对象
    function Item(fn, name) {
      // 函数名称
      this.name = name || fn.name;
      // run方法
      this.run = () => {
        try {
          fn()
        } catch (error) {
          console.log(error);
        }
      };
    }
  }
  /******************** Pjax ********************************/
  // /layout/_plugins/pjax/index.ejs
  // volantis.pjax.send(callBack[,"callBackName"]) 传入pjax:send回调函数
  // volantis.pjax.push(callBack[,"callBackName"]) 传入pjax:complete回调函数
  // volantis.pjax.error(callBack[,"callBackName"]) 传入pjax:error回调函数
  volantis.pjax = {};
  volantis.pjax.method = {
    complete: new RunItem(),
    error: new RunItem(),
    send: new RunItem(),
  };
  volantis.pjax = Object.assign(volantis.pjax, {
    push: volantis.pjax.method.complete.push,
    error: volantis.pjax.method.error.push,
    send: volantis.pjax.method.send.push,
  });
  /******************** RightMenu ********************************/
  // volantis.rightmenu.handle(callBack[,"callBackName"]) 外部菜单项控制
  // 可在 volantis.mouseEvent 处获取右键事件
  volantis.rightmenu = {};
  volantis.rightmenu.method = {
    handle: new RunItem(),
  }
  volantis.rightmenu = Object.assign(volantis.rightmenu, {
    handle: volantis.rightmenu.method.handle.push,
  });
  /********************  Dark Mode  ********************************/
  // /layout/_partial/scripts/darkmode.ejs
  // volantis.dark.mode 当前模式 dark or light
  // volantis.dark.toggle() 暗黑模式触发器
  // volantis.dark.push(callBack[,"callBackName"]) 传入触发器回调函数
  volantis.dark = {};
  volantis.dark.method = {
    toggle: new RunItem(),
  };
  volantis.dark = Object.assign(volantis.dark, {
    push: volantis.dark.method.toggle.push,
  });
  /********************  Message  ********************************/
  // VolantisApp.message
  /********************  isMobile  ********************************/
  // /source/js/app.js
  // volantis.isMobile
  // volantis.isMobileOld
  /********************脚本动态加载函数********************************/
  // volantis.js(src, cb)  cb 可以传入onload回调函数 或者 JSON对象 例如: volantis.js("src", ()=>{}) 或 volantis.js("src", {defer:true,onload:()=>{}})
  // volantis.css(src)

  // 返回Promise对象，如下方法同步加载资源，这利于处理文件资源之间的依赖关系，例如：APlayer 需要在 MetingJS 之前加载
  // (async () => {
  //     await volantis.js("...theme.plugins.aplayer.js.aplayer...")
  //     await volantis.js("...theme.plugins.aplayer.js.meting...")
  // })();

  // 已经加入了setTimeout
  volantis.js = (src, cb) => {
    return new Promise(resolve => {
      setTimeout(function () {
        var HEAD = document.getElementsByTagName("head")[0] || document.documentElement;
        var script = document.createElement("script");
        script.setAttribute("type", "text/javascript");
        if (cb) {
          if (JSON.stringify(cb)) {
            for (let p in cb) {
              if (p == "onload") {
                script[p] = () => {
                  cb[p]()
                  resolve()
                }
              } else {
                script[p] = cb[p]
                script.onload = resolve
              }
            }
          } else {
            script.onload = () => {
              cb()
              resolve()
            };
          }
        } else {
          script.onload = resolve
        }
        script.setAttribute("src", src);
        HEAD.appendChild(script);
      });
    });
  }
  volantis.css = (src) => {
    return new Promise(resolve => {
      setTimeout(function () {
        var link = document.createElement('link');
        link.rel = "stylesheet";
        link.href = src;
        link.onload = resolve;
        document.getElementsByTagName("head")[0].appendChild(link);
      });
    });
  }
  /********************按需加载的插件********************************/
  // volantis.import.jQuery().then(()=>{})
  volantis.import = {
    jQuery: () => {
      if (typeof jQuery == "undefined") {
        return volantis.js("https://unpkg.com/volantis-static@0.0.1654736714924/libs/jquery/dist/jquery.min.js")
      } else {
        return new Promise(resolve => {
          resolve()
        });
      }
    }
  }
  /********************** requestAnimationFrame ********************************/
  // 1、requestAnimationFrame 会把每一帧中的所有 DOM 操作集中起来，在一次重绘或回流中就完成，并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率，一般来说，这个频率为每秒60帧。
  // 2、在隐藏或不可见的元素中，requestAnimationFrame 将不会进行重绘或回流，这当然就意味着更少的的 cpu，gpu 和内存使用量。
  volantis.requestAnimationFrame = (fn)=>{
    if (!window.requestAnimationFrame) {
      window.requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame;
    }
    window.requestAnimationFrame(fn)
  }
  /************************ layoutHelper *****************************************/
  volantis.layoutHelper = (helper, html, opt)=>{
    opt = Object.assign({clean:false, pjax:true}, opt)
    function myhelper(helper, html, clean) {
      volantis.tempDiv = document.createElement("div");
      volantis.tempDiv.innerHTML = html;
      let layoutHelper = document.querySelector("#layoutHelper-"+helper)
      if (layoutHelper) {
        if (clean) {
          layoutHelper.innerHTML = ""
        }
        layoutHelper.append(volantis.tempDiv);
      }
    }
    myhelper(helper, html, opt.clean)
    if (opt.pjax) {
      volantis.pjax.push(()=>{
        myhelper(helper, html, opt.clean)
      },"layoutHelper-"+helper)
    }
  }
  /****************************** 滚动事件处理 ****************************************/
  volantis.scroll = {
    engine: new RunItem(),
    unengine: new RunItem(),
  };
  volantis.scroll = Object.assign(volantis.scroll, {
    push: volantis.scroll.engine.push,
  });
  // 滚动条距离顶部的距离
  volantis.scroll.getScrollTop = () =>{
    let scrollPos;
    if (window.pageYOffset) {
      scrollPos = window.pageYOffset;
    } else if (document.compatMode && document.compatMode != 'BackCompat') {
      scrollPos = document.documentElement.scrollTop;
    } else if (document.body) {
      scrollPos = document.body.scrollTop;
    }
    return scrollPos;
  }
  // 使用 requestAnimationFrame 处理滚动事件
  // `volantis.scroll.del` 中存储了一个数值, 该数值检测一定时间间隔内滚动条滚动的位移, 数值的检测频率是浏览器的刷新频率. 数值为正数时, 表示向下滚动. 数值为负数时, 表示向上滚动.
  volantis.scroll.handleScrollEvents = () => {
    volantis.scroll.lastScrollTop = volantis.scroll.getScrollTop()
    function loop() {
      const scrollTop = volantis.scroll.getScrollTop();
      if (volantis.scroll.lastScrollTop !== scrollTop) {
        volantis.scroll.del = scrollTop - volantis.scroll.lastScrollTop;
        volantis.scroll.lastScrollTop = scrollTop;
        // if (volantis.scroll.del > 0) {
        //   console.log("向下滚动");
        // } else {
        //   console.log("向上滚动");
        // }
        // 注销过期的unengine未滚动事件
        volantis.scroll.unengine.list=[]
        volantis.scroll.engine.start();
      }else{
        volantis.scroll.unengine.start();
      }
      volantis.requestAnimationFrame(loop)
    }
    volantis.requestAnimationFrame(loop)
  }
  volantis.scroll.handleScrollEvents()
  volantis.scroll.ele = null;
  // 触发页面滚动至目标元素位置
  volantis.scroll.to = (ele, option = {}) => {
    if (!ele) return;
    volantis.scroll.ele = ele;
    // 默认配置
    opt = {
      top: ele.getBoundingClientRect().top + document.documentElement.scrollTop,
      behavior: "smooth"
    }
    // 定义配置
    if ("top" in option) {
      opt.top = option.top
    }
    if ("behavior" in option) {
      opt.behavior = option.behavior
    }
    if ("addTop" in option) {
      opt.top += option.addTop
    }
    if (!("observerDic" in option)) {
      option.observerDic = 100
    }
    // 滚动
    window.scrollTo(opt);
    // 监视器
    // 监视并矫正元素滚动到指定位置
    // 用于处理 lazyload 引起的 cls 导致的定位失败问题
    // option.observer = false
    if (option.observer) {
      setTimeout(() => {
        if (volantis.scroll.ele != ele) {
          return
        }
        volantis.scroll.unengine.push(() => {
          let me = ele.getBoundingClientRect().top
          if(!(me >= -option.observerDic && me <= option.observerDic)){
            volantis.scroll.to(ele, option)
          }
          volantis.scroll.unengine.remove("unengineObserver")
        },"unengineObserver")
      },1000)
    }
  }
  /********************** Content Visibility ********************************/
  // 见 source/css/first.styl 如果遇到任何问题 删除 .post-story 即可
  // 一个元素被声明 content-visibility 属性后 如果元素不在 viewport 中 浏览器不会计算其后代元素样式和属性 从而节省 Style & Layout 耗时
  // content-visibility 的副作用: 锚点失效 等等(实验初期 暂不明确), 使用此方法清除样式
  volantis.cleanContentVisibility = ()=>{
    if (document.querySelector(".post-story")) {
      console.log("cleanContentVisibility");
      document.querySelectorAll(".post-story").forEach(e=>{
        e.classList.remove("post-story")
      })
    }
  }
  /******************************************************************************/
  /******************************************************************************/
  /******************************************************************************/
  //图像加载出错时的处理
  function errorImgAvatar(img) {
    img.src = "https://unpkg.com/volantis-static@0.0.1654736714924/media/placeholder/avatar/round/3442075.svg";
    img.onerror = null;
  }
  function errorImgCover(img) {
    img.src = "https://unpkg.com/volantis-static@0.0.1654736714924/media/placeholder/cover/76b86c0226ffd.svg";
    img.onerror = null;
  }
  /******************************************************************************/
</script>

  <!-- import head_end begin -->
  <!-- import head_end end -->
  <!-- Custom Files headEnd begin-->
  
  <!-- Custom Files headEnd end-->
  <!-- front-matter head_end begin -->
  <!-- front-matter head_end end -->
</head>
  <body itemscope itemtype="http://schema.org/WebPage">
    <!-- import body_begin begin-->
    <!-- import body_begin end-->
    <!-- Custom Files bodyBegin begin-->
    
    <!-- Custom Files bodyBegin end-->
    <!-- front-matter body_begin begin -->
    <!-- front-matter body_begin end -->
    <header itemscope itemtype="http://schema.org/WPHeader" id="l_header" class="l_header auto shadow floatable blur show" style='opacity: 0' >
  <div class='container'>
  <div id='wrapper'>
    <div class='nav-sub'>
      <p class="title"></p>
      <ul class='switcher nav-list-h m-phone' id="pjax-header-nav-list">
        <li><a id="s-comment" class="fa-solid fa-comments fa-fw" target="_self"  href="/" onclick="return false;" title="comment"></a></li>
        
          <li><a id="s-toc" class="s-toc fa-solid fa-list fa-fw" target="_self"  href="/" onclick="return false;" title="toc"></a></li>
        
      </ul>
    </div>
		<div class="nav-main">
      
        
        <a class="title flat-box" target="_self" href='/'>
          
            <img no-lazy class='logo' src='https://unpkg.com/volantis-static@0.0.1654736714924/media/org.volantis/blog/Logo-NavBar@3x.png'/>
          
          
          
        </a>
      

			<div class='menu navigation'>
				<ul class='nav-list-h m-pc'>
          
          
          
            
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover"
                href="/" title="博客"
                  
                  
                  
                    active-action="action-home"
                  >
                  <i class='fa-solid fa-rss fa-fw'></i>博客
                </a>
                
              </li>
            
          
          
            
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover"
                href="/categories/" title="分类"
                  
                  
                  
                    active-action="action-categories"
                  >
                  <i class='fa-solid fa-folder-open fa-fw'></i>分类
                </a>
                
              </li>
            
          
          
            
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover"
                href="/tags/" title="标签"
                  
                  
                  
                    active-action="action-tags"
                  >
                  <i class='fa-solid fa-tags fa-fw'></i>标签
                </a>
                
              </li>
            
          
          
            
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover"
                href="/archives/" title="归档"
                  
                  
                  
                    active-action="action-archives"
                  >
                  <i class='fa-solid fa-archive fa-fw'></i>归档
                </a>
                
              </li>
            
          
          
            
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover"
                href="/friends/" title="友链"
                  
                  
                  
                    active-action="action-friends"
                  >
                  <i class='fa-solid fa-link fa-fw'></i>友链
                </a>
                
              </li>
            
          
          
            
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover"
                href="/about/" title="关于"
                  
                  
                  
                    active-action="action-about"
                  >
                  <i class='fa-solid fa-info-circle fa-fw'></i>关于
                </a>
                
              </li>
            
          
          
				</ul>
			</div>
      
      <div class="m_search">
        <form name="searchform" class="form u-search-form">
          <i class="icon fa-solid fa-search fa-fw"></i>
          <input type="text" class="input u-search-input" placeholder="Search..." />
        </form>
      </div>
      

			<ul class='switcher nav-list-h m-phone'>
				
					<li><a class="s-search fa-solid fa-search fa-fw" target="_self" href="/" onclick="return false;" title="search"></a></li>
				
				<li>
          <a class="s-menu fa-solid fa-bars fa-fw" target="_self" href="/" onclick="return false;" title="menu"></a>
          <ul class="menu-phone list-v navigation white-box">
            
              
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover"
                href="/" title="博客"
                  
                  
                  
                    active-action="action-home"
                  >
                  <i class='fa-solid fa-rss fa-fw'></i>博客
                </a>
                
              </li>
            
          
            
              
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover"
                href="/categories/" title="分类"
                  
                  
                  
                    active-action="action-categories"
                  >
                  <i class='fa-solid fa-folder-open fa-fw'></i>分类
                </a>
                
              </li>
            
          
            
              
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover"
                href="/tags/" title="标签"
                  
                  
                  
                    active-action="action-tags"
                  >
                  <i class='fa-solid fa-tags fa-fw'></i>标签
                </a>
                
              </li>
            
          
            
              
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover"
                href="/archives/" title="归档"
                  
                  
                  
                    active-action="action-archives"
                  >
                  <i class='fa-solid fa-archive fa-fw'></i>归档
                </a>
                
              </li>
            
          
            
              
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover"
                href="/friends/" title="友链"
                  
                  
                  
                    active-action="action-friends"
                  >
                  <i class='fa-solid fa-link fa-fw'></i>友链
                </a>
                
              </li>
            
          
            
              
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover"
                href="/about/" title="关于"
                  
                  
                  
                    active-action="action-about"
                  >
                  <i class='fa-solid fa-info-circle fa-fw'></i>关于
                </a>
                
              </li>
            
          
            
          </ul>
        </li>
			</ul>

      <!-- Custom Files header begin -->
      
      <!-- Custom Files header end -->
		</div>
	</div>
  </div>
</header>

    <div id="l_body">
      <div id="l_cover">
  
    
      <!-- see: /layout/_partial/scripts/_ctrl/coverCtrl.ejs -->
      <div id="none" class='cover-wrapper post dock' style="display: none;">
        
  <div class='cover-bg lazyload placeholder' data-bg="https://gcore.jsdelivr.net/gh/MHG-LAB/cron@gh-pages/bing/bing.jpg"></div>

<div class='cover-body'>
  <div class='top'>
    
    
      <p class="title">Volantis</p>
    
    
  </div>
  <div class='bottom'>
    <div class='menu navigation'>
      <div class='list-h'>
        
          
            <a href="/v4/getting-started/"
              
              
              active-action="action-v4getting-started">
              <img src='https://unpkg.com/volantis-static@0.0.1654736714924/media/twemoji/assets/svg/1f5c3.svg'><p>文档</p>
            </a>
          
            <a href="/faqs/"
              
              
              active-action="action-faqs">
              <img src='https://unpkg.com/volantis-static@0.0.1654736714924/media/twemoji/assets/svg/1f516.svg'><p>帮助</p>
            </a>
          
            <a href="/examples/"
              
              
              active-action="action-examples">
              <img src='https://unpkg.com/volantis-static@0.0.1654736714924/media/twemoji/assets/svg/1f396.svg'><p>示例</p>
            </a>
          
            <a href="/contributors/"
              
              
              active-action="action-contributors">
              <img src='https://unpkg.com/volantis-static@0.0.1654736714924/media/twemoji/assets/svg/1f389.svg'><p>社区</p>
            </a>
          
            <a href="/archives/"
              
              
              active-action="action-archives">
              <img src='https://unpkg.com/volantis-static@0.0.1654736714924/media/twemoji/assets/svg/1f4f0.svg'><p>博客</p>
            </a>
          
            <a target="_blank" rel="noopener" href="https://github.com/volantis-x/hexo-theme-volantis/"
              
              
              active-action="action-https:githubcomvolantis-xhexo-theme-volantis">
              <img src='https://unpkg.com/volantis-static@0.0.1654736714924/media/twemoji/assets/svg/1f9ec.svg'><p>源码</p>
            </a>
          
        
      </div>
    </div>
  </div>
</div>

        <div id="scroll-down" style="display: none;"><i class="fa fa-chevron-down scroll-down-effects"></i></div>
      </div>
    
  
</div>

      <div id="safearea">
        <div class="body-wrapper">
          
<div id="l_main" class=''>
  <article itemscope itemtype="http://schema.org/Article" class="article post white-box reveal md shadow floatable blur article-type-post" id="post" itemscope itemprop="blogPost">
  <link itemprop="mainEntityOfPage" href="http://8.219.11.28/2024/02/23/前后端-SpringBoot/">
  <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
    <meta itemprop="name" content="欢迎来到我的个人博客~">
  </span>
  <span hidden itemprop="post" itemscope itemtype="http://schema.org/Post">
    <meta itemprop="name" content="欢迎来到我的个人博客~">
    <meta itemprop="description" content="这些技术大部分是自己总结的，非官方">
  </span>
  


  
    <span hidden>
      <meta itemprop="image" content="https://unpkg.com/volantis-static@0.0.1654736714924/media/org.volantis/blog/favicon/android-chrome-192x192.png">
    </span>
  
  <div class="article-meta" id="top">
    
    
    
      <span hidden itemprop="name headline">
        
      </span>
    
  </div>


  <div id="layoutHelper-page-plugins"></div>
  <div id="post-body" itemprop="articleBody">
    <h1 id="SpringBoot基础"><a href="#SpringBoot基础" class="headerlink" title="SpringBoot基础"></a><strong>SpringBoot</strong>基础</h1><h2 id="创建springboot的流程"><a href="#创建springboot的流程" class="headerlink" title="创建springboot的流程:"></a><strong>创建springboot的流程:</strong></h2><h5 id="1-maven-项目"><a href="#1-maven-项目" class="headerlink" title="1.maven 项目"></a>1.maven 项目</h5><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!--    所有springboot项目都必须继承自 spring-boot-starter-parent --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">parent</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-parent<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>3.0.5<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">parent</span>&gt;</span></span><br></pre></td></tr></table></figure>

<h5 id="2-导入需要的场景启动器"><a href="#2-导入需要的场景启动器" class="headerlink" title="2.导入需要的场景启动器"></a>2.导入需要的场景启动器</h5><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">   <span class="tag">&lt;<span class="name">dependencies</span>&gt;</span></span><br><span class="line"><span class="comment">&lt;!--        web开发的场景启动器 --&gt;</span></span><br><span class="line">       <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">           <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">           <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-web<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">       <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;/<span class="name">dependencies</span>&gt;</span></span><br><span class="line"></span><br></pre></td></tr></table></figure>

<h5 id="3-写对应业务"><a href="#3-写对应业务" class="headerlink" title="3.写对应业务"></a>3.写对应业务</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">HelloController</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@GetMapping(&quot;/hello&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">hello</span><span class="params">()</span>&#123;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;Hello,Spring Boot 3!&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h5 id="4-测试"><a href="#4-测试" class="headerlink" title="4.测试"></a>4.测试</h5><p>​	直接访问localhost:port</p>
<h5 id="5-打包"><a href="#5-打包" class="headerlink" title="5.打包"></a>5.打包</h5><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!--    SpringBoot应用打包插件--&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">build</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">plugins</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">plugin</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-maven-plugin<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="name">plugin</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">plugins</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">build</span>&gt;</span></span><br></pre></td></tr></table></figure>

<h5 id="6-任意运行"><a href="#6-任意运行" class="headerlink" title="6.任意运行"></a>6.任意运行</h5><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">	`	mvn clean package`把项目打成可执行的jar包</span><br><span class="line"></span><br><span class="line">`		java -jar demo.jar`启动项目  /linux</span><br></pre></td></tr></table></figure>

<h3 id="或者通过springinitailzer创建"><a href="#或者通过springinitailzer创建" class="headerlink" title="或者通过springinitailzer创建"></a><strong>或者通过springinitailzer创建</strong></h3><p>直接在创建项目的时候选择spring</p>
<h2 id="简化配置"><a href="#简化配置" class="headerlink" title="**简化配置 **"></a>**简化配置 **</h2><h5 id="1-直接在application-yml中改"><a href="#1-直接在application-yml中改" class="headerlink" title="1.直接在application.yml中改"></a>1.<strong>直接在application.yml中改</strong></h5><p>linux部署后 需要修改配置 直接在项目目录下创建文件配置即可</p>
<h5 id="2-application-yml中的每一个属性-对应着某个包某个类的某个对象的属性"><a href="#2-application-yml中的每一个属性-对应着某个包某个类的某个对象的属性" class="headerlink" title="2.application.yml中的每一个属性 对应着某个包某个类的某个对象的属性**"></a>2.<strong>application.yml</strong>中的每一个属性 对应着某个包某个类的某个对象的属性**</h5><p>例如 server: port 对应ServerPort类的port属性</p>
<h2 id="第三方jar包"><a href="#第三方jar包" class="headerlink" title="**第三方jar包 **"></a>**第三方jar包 **</h2><p><strong>boot父项目没有管理的需要自行声明好</strong></p>
<p>例如:</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!-- https://mvnrepository.com/artifact/com.alibaba/druid --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.alibaba<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>druid<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>1.2.16<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"></span><br></pre></td></tr></table></figure>





<h2 id="ioc容器"><a href="#ioc容器" class="headerlink" title="ioc容器"></a><strong>ioc容器</strong></h2><p>ioc就是一个对象 </p>
<p>具体看spring6.md</p>
<h2 id="应用启动"><a href="#应用启动" class="headerlink" title="应用启动"></a>应用启动</h2><h5 id="1-Spring应用启动的步骤"><a href="#1-Spring应用启动的步骤" class="headerlink" title="1.Spring应用启动的步骤:"></a>1.Spring应用启动的步骤:</h5><h6 id="老老实实版-直接SpringApplication-run"><a href="#老老实实版-直接SpringApplication-run" class="headerlink" title="老老实实版 直接SpringApplication.run()"></a>老老实实版 直接SpringApplication.run()</h6><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MainApplication</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="comment">//获取ioc容器对象</span></span><br><span class="line">        <span class="type">var</span> <span class="variable">ioc</span> <span class="operator">=</span> SpringApplication.run(MainApplication.class, args);</span><br><span class="line"></span><br><span class="line">        <span class="comment">//遍历容器中所有组件的名字</span></span><br><span class="line">        String[] beanDefinitionNames = ioc.getBeanDefinitionNames();</span><br><span class="line">        Arrays.stream(beanDefinitionNames).forEach(System.out::println);</span><br><span class="line"></span><br><span class="line">        <span class="comment">//查询自定义的组件</span></span><br><span class="line">        System.out.println(ioc.getBean(<span class="string">&quot;zhangming&quot;</span>));</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h6 id="通过ApplicationBuilder"><a href="#通过ApplicationBuilder" class="headerlink" title="通过ApplicationBuilder"></a>通过ApplicationBuilder</h6><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="meta">@MapperScan(&quot;MainApplication.generator.mapper&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MainApplication</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        log.info(<span class="string">&quot;项目启动了&quot;</span>);</span><br><span class="line"><span class="comment">//        SpringApplication.run(MainApplication.class, args);</span></span><br><span class="line"></span><br><span class="line">        <span class="keyword">new</span> <span class="title class_">SpringApplicationBuilder</span>()</span><br><span class="line">                .sources(MainApplication.class)</span><br><span class="line">                .properties(<span class="string">&quot;server.port=5001&quot;</span>)		<span class="comment">//在这里可以进行构造</span></span><br><span class="line">                .build()</span><br><span class="line">                .run();</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>







<h5 id="2-SpringApplication和SpringContext的区别"><a href="#2-SpringApplication和SpringContext的区别" class="headerlink" title="2.SpringApplication和SpringContext的区别"></a>2.SpringApplication和SpringContext的区别</h5><ol>
<li><strong>SpringApplication:</strong><ul>
<li><code>SpringApplication</code> 是 Spring Boot 提供的一个用于启动 Spring 应用的类。</li>
<li>它封装了启动 Spring Boot 应用所需的各种设置和配置，简化了应用程序的启动过程。</li>
<li>提供了多种启动应用的方式，包括静态的 <code>run</code> 方法、构造函数、带参数的 <code>run</code> 方法等。</li>
</ul>
</li>
<li><strong>Spring Context（Spring 容器）:</strong><ul>
<li>Spring 容器是 Spring 框架的核心部分，负责管理和组织应用中的各个组件（例如 bean）。</li>
<li>在 Spring 应用中，容器负责创建、配置、组装和管理这些组件，使它们能够协同工作。</li>
<li>典型的 Spring 容器有 <code>ApplicationContext</code> 接口的实现，如 <code>AnnotationConfigApplicationContext</code>、<code>ClassPathXmlApplicationContext</code> 等。</li>
</ul>
</li>
<li><strong>联系:</strong><ul>
<li><code>SpringApplication</code> 使用 Spring 容器来加载应用程序上下文。当你使用 <code>SpringApplication.run</code> 启动应用时，它会创建一个 Spring 容器，并加载应用程序上下文。</li>
<li><code>SpringApplication</code> 类通常与 Spring Boot 注解 <code>@SpringBootApplication</code> 一起使用，这个注解包含了 <code>@Configuration</code>、<code>@EnableAutoConfiguration</code> 和 <code>@ComponentScan</code>，这些注解一起帮助配置 Spring 容器。</li>
<li>在 Spring Boot 应用中，<code>SpringApplication</code> 是用于启动整个应用的入口点，而 Spring 容器负责管理应用中的组件和依赖关系。</li>
</ul>
</li>
</ol>
<h2 id="默认扫描"><a href="#默认扫描" class="headerlink" title="默认扫描"></a>默认扫描</h2><p>默认只能扫描自己主程序所在的包及其下面的子包**</p>
<h2 id="自动配置"><a href="#自动配置" class="headerlink" title="自动配置"></a>自动配置</h2><p><strong>原理</strong></p>
<p><strong>导入starter–&gt; 生效xxxxAutoConfiguration –&gt; 组件 –&gt; xxxProperties –&gt; 配置文件</strong></p>
<p>意为，我们导入对应的场景启动器，也就是starter，这个是在pom.xml中导入的 ，然后springboot会让xxxAutoConfigration生效，一般这是一个自动配置类，由@AutoConfigration注解修饰，然后导入一些必要的组件，并且通过配置文件生效</p>
<p><code>注解解释</code>:</p>
<p><code>@EnableAutoConfiguration</code>:使得 Spring Boot 能够根据项目的依赖关系和配置信息，自动地配置应用程序的各个组件</p>
<p><code>@EnableAutoConfiguration</code>:用于启用自动配置功能</p>
<p><code>@import</code>:用于在配置类中导入其他配置类或组件</p>
<p><code>@EnableConfigurationProperties</code>:用于启用特定的配置属性类，从而让这些属性类能够被 Spring 容器管理</p>
<p><code>@ConfigurationProperties</code>：用于将配置文件的配置绑定到配置类上</p>
<p>下面以redis为例:</p>
<p>导入redis</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">          <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">          <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-data-redis<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>在Spring Boot中，通过<code>@EnableAutoConfiguration</code>注解来开启自动配置功能。而<code>@AutoConfiguration</code>注解则是<code>@EnableAutoConfiguration</code>注解的元注解，用于标记自动配置类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//redis自动配置类就随着pom导入进来了</span></span><br><span class="line"><span class="meta">@AutoConfiguration</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//导入某个组件的注解</span></span><br><span class="line"><span class="meta">@Import(&#123;LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class&#125;)</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//条件注解</span></span><br><span class="line"><span class="meta">@ConditionalOnClass(&#123;RedisOperations.class&#125;)</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//配置类的注解</span></span><br><span class="line"><span class="meta">@EnableConfigurationProperties(&#123;RedisProperties.class&#125;)</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//然后下面所有的bean 都会被ioc容器管理</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">RedisAutoConfiguration</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">RedisAutoConfiguration</span><span class="params">()</span> &#123;</span><br><span class="line">    &#125;</span><br><span class="line">	<span class="comment">//这里向ioc容器注入了一个RedisTemplate对象</span></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="meta">@ConditionalOnMissingBean(</span></span><br><span class="line"><span class="meta">        name = &#123;&quot;redisTemplate&quot;&#125;</span></span><br><span class="line"><span class="meta">    )</span></span><br><span class="line">    <span class="meta">@ConditionalOnSingleCandidate(RedisConnectionFactory.class)</span></span><br><span class="line">    <span class="keyword">public</span> RedisTemplate&lt;Object, Object&gt; <span class="title function_">redisTemplate</span><span class="params">(RedisConnectionFactory redisConnectionFactory)</span> &#123;</span><br><span class="line">        RedisTemplate&lt;Object, Object&gt; template = <span class="keyword">new</span> <span class="title class_">RedisTemplate</span>();</span><br><span class="line">        template.setConnectionFactory(redisConnectionFactory);</span><br><span class="line">        <span class="keyword">return</span> template;</span><br><span class="line">    &#125;</span><br><span class="line">	<span class="comment">//这里向ioc容器注入了一个StringRedisTemplate对象</span></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="meta">@ConditionalOnMissingBean</span></span><br><span class="line">    <span class="meta">@ConditionalOnSingleCandidate(RedisConnectionFactory.class)</span></span><br><span class="line">    <span class="keyword">public</span> StringRedisTemplate <span class="title function_">stringRedisTemplate</span><span class="params">(RedisConnectionFactory redisConnectionFactory)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">StringRedisTemplate</span>(redisConnectionFactory);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>验证 确实能拿到redis工厂对象</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">	</span><br><span class="line"><span class="type">var</span> <span class="variable">ioc</span> <span class="operator">=</span> SpringApplication.run(MainApplication.class, args);</span><br><span class="line">   <span class="type">var</span> <span class="variable">obj</span> <span class="operator">=</span> ioc.getBean(RedisConnectionFactory.class);</span><br><span class="line">   System.out.println(obj);</span><br></pre></td></tr></table></figure>

<p>redis配置类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@ConfigurationProperties(prefix = &quot;spring.data.redis&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">RedisProperties</span> &#123;</span><br></pre></td></tr></table></figure>

<p>yml中可以修改配置类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">spring:</span><br><span class="line">  data:</span><br><span class="line">    redis:</span><br><span class="line">      host: localhost</span><br></pre></td></tr></table></figure>







<h2 id="组件注册"><a href="#组件注册" class="headerlink" title="组件注册"></a>组件注册</h2><h5 id="1-通过-ComponentScan扫描指定包，将包下的标注-Controller、-Service、-Repository、-Component的bean注册到IOC容器中"><a href="#1-通过-ComponentScan扫描指定包，将包下的标注-Controller、-Service、-Repository、-Component的bean注册到IOC容器中" class="headerlink" title="1.通过@ComponentScan扫描指定包，将包下的标注@Controller、@Service、@Repository、@Component的bean注册到IOC容器中"></a>1.通过@ComponentScan扫描指定包，将包下的标注@Controller、@Service、@Repository、@Component的bean注册到<a target="_blank" rel="noopener" href="https://so.csdn.net/so/search?q=IOC%E5%AE%B9%E5%99%A8&spm=1001.2101.3001.7020">IOC容器</a>中</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="meta">@ComponentScan(&quot;com.mzp.bean&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">TestLifeCycleConfig</span> &#123;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Pig</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> String name;</span><br><span class="line">    <span class="keyword">private</span> Integer age;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//ioc获取bean</span></span><br><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MainApplication</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="type">var</span> <span class="variable">ioc</span> <span class="operator">=</span> SpringApplication.run(MainApplication.class, args);</span><br><span class="line">        <span class="type">var</span> <span class="variable">bean</span> <span class="operator">=</span> ioc.getBean(Pig.class);</span><br><span class="line">        bean.setAge(<span class="number">18</span>);</span><br><span class="line">        bean.setName(<span class="string">&quot;林依帆&quot;</span>);</span><br><span class="line">        System.out.println(bean);</span><br><span class="line"></span><br><span class="line">        <span class="type">var</span> <span class="variable">bean1</span> <span class="operator">=</span> ioc.getBean(Pig.class);</span><br><span class="line">        bean1.setName(<span class="string">&quot;张明&quot;</span>);</span><br><span class="line">        bean1.setAge(<span class="number">20</span>);</span><br><span class="line">        System.out.println(bean1);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h5 id="2-在配置类-Configuration-中使用-Bean注解将方法返回值对象注册到IOC容器中，id默认是方法名称，可通过value参数指定id"><a href="#2-在配置类-Configuration-中使用-Bean注解将方法返回值对象注册到IOC容器中，id默认是方法名称，可通过value参数指定id" class="headerlink" title="2.在配置类(@Configuration)中使用@Bean注解将方法返回值对象注册到IOC容器中，id默认是方法名称，可通过value参数指定id"></a>2.在配置类(@Configuration)中使用@Bean注解将方法返回值对象注册到IOC容器中，id默认是方法名称，可通过value参数指定id</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">TestConfig</span> &#123;</span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="keyword">public</span> Pig <span class="title function_">getPig</span><span class="params">()</span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Pig</span>(<span class="string">&quot;张明&quot;</span>,<span class="number">18</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//ioc调用</span></span><br><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MainApplication</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="type">var</span> <span class="variable">ioc</span> <span class="operator">=</span> SpringApplication.run(MainApplication.class, args);</span><br><span class="line">        System.out.println(ioc.getBean(Pig.class));</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h5 id="3-通过-Import注解将Bean注册到IOC容器中"><a href="#3-通过-Import注解将Bean注册到IOC容器中" class="headerlink" title="3.通过@Import注解将Bean注册到IOC容器中"></a>3.通过@Import注解将Bean注册到IOC容器中</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="meta">@Import(Pig.class)</span></span><br><span class="line"><span class="comment">//@Import(外部类.class)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MainApplication</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="type">var</span> <span class="variable">ioc</span> <span class="operator">=</span> SpringApplication.run(MainApplication.class, args);</span><br><span class="line">        System.out.println(ioc.getBean(Pig.class));</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h5 id="4-工厂bean"><a href="#4-工厂bean" class="headerlink" title="4.工厂bean"></a>4.工厂bean</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//工厂bean类</span></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">PigFactory</span> <span class="keyword">implements</span> <span class="title class_">FactoryBean</span>&lt;Pig&gt; &#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//通过该方法返回实际bean对象</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> Pig <span class="title function_">getObject</span><span class="params">()</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Pig</span>(<span class="string">&quot;张明&quot;</span>,<span class="number">18</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//返回实际bean的class类型</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> Class&lt;?&gt; getObjectType() &#123;</span><br><span class="line">        <span class="keyword">return</span> Pig.class;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//设置bean作用域：单例、多实例</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">isSingleton</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> FactoryBean.<span class="built_in">super</span>.isSingleton();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//实现</span></span><br><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="meta">@Import(PigFactory.class)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MainApplication</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        <span class="comment">//先拿到ioc</span></span><br><span class="line">        <span class="type">var</span> <span class="variable">ioc</span> <span class="operator">=</span> SpringApplication.run(MainApplication.class, args);</span><br><span class="line">        <span class="comment">//拿到工厂</span></span><br><span class="line">        <span class="type">var</span> <span class="variable">pc</span> <span class="operator">=</span> ioc.getBean(PigFactory.class);</span><br><span class="line">        <span class="comment">//通过工厂bean来拿到bean</span></span><br><span class="line">        <span class="type">var</span> <span class="variable">pg</span> <span class="operator">=</span> pc.getObject();</span><br><span class="line">        System.out.println(pg);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>





<h2 id="条件注解"><a href="#条件注解" class="headerlink" title="条件注解"></a>条件注解</h2><h5 id="ConditionalOnClass-如果容器存在Logger-class则触发-也就是pom里有"><a href="#ConditionalOnClass-如果容器存在Logger-class则触发-也就是pom里有" class="headerlink" title="@ConditionalOnClass 如果容器存在Logger.class则触发 也就是pom里有"></a>@ConditionalOnClass 如果容器存在Logger.class则触发 也就是<u>pom</u>里有</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="meta">@ConditionalOnClass(Logger.class)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Pig</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> String name;</span><br><span class="line">    <span class="keyword">private</span> Integer age;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h5 id="ConditionalOnMissingClass-类路径不存在这个类则触发"><a href="#ConditionalOnMissingClass-类路径不存在这个类则触发" class="headerlink" title="@ConditionalOnMissingClass 类路径不存在这个类则触发"></a>@ConditionalOnMissingClass 类路径不存在这个类则触发</h5><h5 id="ConditionalOnBean-如果容器中存在这个Pig-bean组件-则触发"><a href="#ConditionalOnBean-如果容器中存在这个Pig-bean组件-则触发" class="headerlink" title="@ConditionalOnBean 如果容器中存在这个Pig bean组件 则触发"></a>@ConditionalOnBean 如果容器中存在这个Pig bean组件 则触发</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@ConditionalOnBean(Pig.class)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">User</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> String name;</span><br><span class="line">    <span class="keyword">private</span> String password;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h5 id="注解应用场景"><a href="#注解应用场景" class="headerlink" title="注解应用场景:"></a>注解应用场景:</h5><p>在软件开发中，**<u>文件系统</u>**是必须的，但是系统的特点不一样，有些用户希望将文件保存在自己的服务器上，有些用户则没这种要求，这时候，文件可以保存在云上，也可以保存在自建文件系统上</p>
<p>例如 在appconfig2类中 指定了一个bean想要交给ioc 必须经过@ConditionalOnClass 中</p>
<p><strong>容器中存在FastsqlEx..这个类 则将user1 交给ioc管理</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//配置类用@Configuration来修饰</span></span><br><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Appconfig2</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@ConditionalOnClass(FastsqlException.class)</span></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="keyword">public</span> User <span class="title function_">user1</span><span class="params">()</span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">User</span>(<span class="string">&quot;zhangming&quot;</span>,<span class="string">&quot;zmzm1036&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>也可以放在配置类上 这样整个配置类都会生效</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//放在这里 如果pom中有Fast..这个类 则这个配置类生效</span></span><br><span class="line"><span class="meta">@ConditionalOnClass(FastsqlException.class)</span></span><br><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Appconfig2</span> &#123;</span><br><span class="line"></span><br><span class="line"><span class="comment">//    @ConditionalOnClass(FastsqlException.class)</span></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="keyword">public</span> User <span class="title function_">user1</span><span class="params">()</span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">User</span>(<span class="string">&quot;zhangming&quot;</span>,<span class="string">&quot;zmzm1036&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h2 id="属性绑定注解"><a href="#属性绑定注解" class="headerlink" title="属性绑定注解"></a>属性绑定注解</h2><h5 id="ConfigurationProperties"><a href="#ConfigurationProperties" class="headerlink" title="@ConfigurationProperties"></a>@ConfigurationProperties</h5><h5 id="EableConfigurationProperties"><a href="#EableConfigurationProperties" class="headerlink" title="@EableConfigurationProperties"></a>@EableConfigurationProperties</h5><p><strong>可以将组件bean的属性值和配置文件的配置项进行绑定</strong> </p>
<h5 id="使用步骤"><a href="#使用步骤" class="headerlink" title="使用步骤:"></a>使用步骤:</h5><p><strong>1.给容器中注册组件</strong></p>
<p>注:@component和@bean的区别: @Component是泛大的 @bean是精确的</p>
<p>@component和@bean只能用一个</p>
<h5 id="在使用-ConfigurationProperties时需要先注册组件"><a href="#在使用-ConfigurationProperties时需要先注册组件" class="headerlink" title="在使用@ConfigurationProperties时需要先注册组件"></a>在使用@ConfigurationProperties时需要先注册组件</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="meta">@ConfigurationProperties(prefix = &quot;pig&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Pig</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> String name;</span><br><span class="line">    <span class="keyword">private</span> Integer age;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//application.yml</span></span><br><span class="line">pig:</span><br><span class="line">  name: <span class="string">&quot;张明&quot;</span></span><br><span class="line">  age: <span class="number">18</span></span><br><span class="line">     </span><br><span class="line">      </span><br><span class="line"><span class="comment">//使用</span></span><br></pre></td></tr></table></figure>



<h5 id="使用-EableConfigurationProperties-一般用于导入第三方的包-表示允许配置第三包的配置"><a href="#使用-EableConfigurationProperties-一般用于导入第三方的包-表示允许配置第三包的配置" class="headerlink" title="使用@EableConfigurationProperties 一般用于导入第三方的包  表示允许配置第三包的配置"></a>使用@EableConfigurationProperties 一般用于导入第三方的包  表示允许配置第三包的配置</h5><h5 id="相当于-ConfigurationProperties-Import"><a href="#相当于-ConfigurationProperties-Import" class="headerlink" title="相当于@ConfigurationProperties + @Import"></a>相当于@ConfigurationProperties + @Import</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//配置类</span></span><br><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="meta">@EnableConfigurationProperties(第三方.class)</span>  <span class="comment">//把user类绑定 但是需要在对应的</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Appconfig</span> &#123;</span><br><span class="line">    </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h5 id="ConfigurationProperties-prefix-“user”-也可以直接放在配置类中"><a href="#ConfigurationProperties-prefix-“user”-也可以直接放在配置类中" class="headerlink" title="@ConfigurationProperties(prefix &#x3D; “user”)也可以直接放在配置类中"></a>@ConfigurationProperties(prefix &#x3D; “user”)也可以直接放在配置类中</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@ConditionalOnClass(FastsqlException.class)</span></span><br><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Appconfig2</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@ConfigurationProperties(prefix = &quot;user&quot;)</span></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="keyword">public</span> User <span class="title function_">user1</span><span class="params">()</span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">User</span>(<span class="string">&quot;zhangming&quot;</span>,<span class="string">&quot;zmzm1036&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">user:</span><br><span class="line">  name: zssz</span><br><span class="line">  password: zmzm1036123</span><br></pre></td></tr></table></figure>





<h2 id="复杂对象的yml表示"><a href="#复杂对象的yml表示" class="headerlink" title="复杂对象的yml表示"></a>复杂对象的yml表示</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="meta">@Data</span></span><br><span class="line"><span class="meta">@NoArgsConstructor</span></span><br><span class="line"><span class="meta">@AllArgsConstructor</span></span><br><span class="line"><span class="meta">@ToString</span></span><br><span class="line"><span class="meta">@ConfigurationProperties(prefix=&quot;pig&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Pig</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> String name;</span><br><span class="line">    <span class="keyword">private</span> Integer age;</span><br><span class="line">    <span class="keyword">private</span> User user;</span><br><span class="line">    <span class="keyword">private</span> List&lt;String&gt; parents;<span class="comment">//集合类型</span></span><br><span class="line">    <span class="keyword">private</span> Map&lt;Integer,String&gt; homes;<span class="comment">//map类型</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>properties:**</p>
<figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">pig.name</span>=<span class="string">&quot;perpo&quot;</span></span><br><span class="line"><span class="attr">pig.age</span>=<span class="string">&quot;18&quot;</span></span><br><span class="line"><span class="attr">pig.user.name</span>=<span class="string">&quot;zhangsan&quot;</span></span><br><span class="line"><span class="attr">pig.user.age</span>=<span class="string">18**</span></span><br><span class="line"><span class="attr">pig.parents[0]</span> = <span class="string">&quot;zhang&quot;</span></span><br><span class="line"><span class="attr">pig.homes.int</span>=<span class="string">&quot;hello&quot;</span></span><br></pre></td></tr></table></figure>

<p>​	</p>
<p>yml:</p>
<figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">pig</span>:<span class="string"></span></span><br><span class="line">  <span class="attr">name</span>: <span class="string">&quot;zhang&quot;</span></span><br><span class="line">  <span class="attr">age</span>: <span class="string">18</span></span><br><span class="line">  <span class="attr">user</span>:<span class="string"></span></span><br><span class="line">    <span class="attr">name</span>: <span class="string">李四</span></span><br><span class="line">    <span class="attr">age</span>: <span class="string">20</span></span><br><span class="line">  <span class="attr">parents</span>: <span class="string">[&quot;abd&quot;,&quot;bcd&quot;]</span></span><br><span class="line">  <span class="attr">homes</span>:<span class="string"></span></span><br><span class="line">     <span class="attr">1</span>: <span class="string">zhangsan</span></span><br><span class="line">     <span class="attr">2</span>: <span class="string">lisi</span></span><br></pre></td></tr></table></figure>





<h2 id="日志整合原理"><a href="#日志整合原理" class="headerlink" title="日志整合原理"></a>日志整合原理</h2><h5 id="日志格式"><a href="#日志格式" class="headerlink" title="日志格式"></a>日志格式</h5><ul>
<li><p><strong>只会打印指定级别及以上级别的日志</strong></p>
</li>
<li><p>ALL：打印所有日志</p>
</li>
<li><p>TRACE：追踪框架详细流程日志，一般不使用</p>
</li>
<li><p>DEBUG：开发调试细节日志</p>
</li>
<li><p>INFO：关键、感兴趣信息日志</p>
</li>
<li><p>WARN：警告但不是错误的信息日志，比如：版本过时</p>
</li>
<li><p>ERROR：业务错误日志，比如出现各种异常</p>
</li>
<li><p>FATAL：致命错误日志，比如jvm系统崩溃</p>
</li>
<li><p>OFF：关闭所有日志记录</p>
</li>
</ul>
<h5 id="时间-精确到毫秒-日志类型-日志进程-日志线程-进行的java类-日志信息"><a href="#时间-精确到毫秒-日志类型-日志进程-日志线程-进行的java类-日志信息" class="headerlink" title="时间 精确到毫秒  日志类型  日志进程  [日志线程]  进行的java类  日志信息"></a>时间 精确到毫秒  日志类型  日志进程  [日志线程]  进行的java类  日志信息</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">2023</span>-<span class="number">12</span>-09T13:<span class="number">22</span>:<span class="number">15.480</span>+08:<span class="number">00</span>  INFO <span class="number">8408</span> --- [           main] MainApplication.MainApplication          : No active profile set, falling back to <span class="number">1</span> <span class="keyword">default</span> profile: <span class="string">&quot;default&quot;</span></span><br></pre></td></tr></table></figure>

<h5 id="日志格式修改"><a href="#日志格式修改" class="headerlink" title="日志格式修改"></a>日志格式修改</h5><figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">logging:</span></span><br><span class="line">  <span class="attr">pattern:</span></span><br><span class="line">    <span class="attr">console:</span> <span class="string">&#x27;%d&#123;yyyy-MM-dd HH:mm:ss&#125; %-5level [%thread] %logger&#123;15&#125; ==&gt;日志信息 -&gt; %msg%n&#x27;</span></span><br></pre></td></tr></table></figure>

<h5 id="使用日志"><a href="#使用日志" class="headerlink" title="使用日志"></a>使用日志</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">HelloController</span> &#123;</span><br><span class="line">    <span class="meta">@GetMapping(&quot;/hello&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">hello</span><span class="params">()</span>&#123;</span><br><span class="line"><span class="comment">//        Logger logger = LoggerFactory.getLogger(getClass());</span></span><br><span class="line">        log.info(<span class="string">&quot;哈哈哈哈方法进来了&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;Hello,Spring Boot 3!&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h5 id="日志输出到文件"><a href="#日志输出到文件" class="headerlink" title="日志输出到文件"></a>日志输出到文件</h5><figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">logging:</span></span><br><span class="line">  <span class="attr">file:</span></span><br><span class="line">    <span class="attr">name:</span> <span class="string">logfile</span></span><br><span class="line">  </span><br><span class="line">  </span><br><span class="line">  </span><br><span class="line"> <span class="comment">#输出到D盘</span></span><br><span class="line"> <span class="attr">logging:</span></span><br><span class="line">  <span class="attr">file:</span></span><br><span class="line">    <span class="attr">path:</span> <span class="string">&quot;D://&quot;</span></span><br></pre></td></tr></table></figure>

<h5 id="文件归档与切割"><a href="#文件归档与切割" class="headerlink" title="文件归档与切割"></a>文件归档与切割</h5><p>归档：每天的日志单独存到每天的日志中</p>
<p>切割:   每个文件要求10mb,超过的话就切割成两个文件</p>
<p><strong>日志存档的文件名格式</strong>（默认值：${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz）</p>
<figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">logging.logback.rollingpolicy.file-name-pattern</span> </span><br></pre></td></tr></table></figure>

<p>存档前，<strong>每个日志文件的最大大小</strong></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">logging.logback.rollingpolicy.max-file-size</span><br></pre></td></tr></table></figure>



<h2 id="热部署"><a href="#热部署" class="headerlink" title="热部署"></a>热部署</h2><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">          <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">          <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-devtools<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">          <span class="tag">&lt;<span class="name">scope</span>&gt;</span>runtime<span class="tag">&lt;/<span class="name">scope</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>







<h2 id="Web开发相关"><a href="#Web开发相关" class="headerlink" title="Web开发相关"></a>Web开发相关</h2><h4 id="所有的MVC配置-在WebMvcAutoConfiguration中"><a href="#所有的MVC配置-在WebMvcAutoConfiguration中" class="headerlink" title="所有的MVC配置 在WebMvcAutoConfiguration中"></a>所有的MVC配置 在WebMvcAutoConfiguration中</h4><h2 id="Web自动配置原理"><a href="#Web自动配置原理" class="headerlink" title="Web自动配置原理"></a>Web自动配置原理</h2><h5 id="引入场景"><a href="#引入场景" class="headerlink" title="引入场景"></a>引入场景</h5><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">&lt;dependency&gt;</span><br><span class="line">    &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;</span><br><span class="line">    &lt;artifactId&gt;spring-boot-starter-web&lt;/artifactId&gt;</span><br><span class="line">&lt;/dependency&gt;</span><br></pre></td></tr></table></figure>

<h5 id="里面包含了-autoconfigure自动配置功能"><a href="#里面包含了-autoconfigure自动配置功能" class="headerlink" title="里面包含了 autoconfigure自动配置功能:"></a>里面包含了 autoconfigure自动配置功能:</h5><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">&lt;dependency&gt;</span><br><span class="line">     &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;</span><br><span class="line">     &lt;artifactId&gt;spring-boot-autoconfigure&lt;/artifactId&gt;</span><br><span class="line">     &lt;version&gt;3.0.5&lt;/version&gt;</span><br><span class="line">     &lt;scope&gt;compile&lt;/scope&gt;</span><br><span class="line">   &lt;/dependency&gt;</span><br></pre></td></tr></table></figure>

<h5 id="因为springboot应用开启了自动配置"><a href="#因为springboot应用开启了自动配置" class="headerlink" title="因为springboot应用开启了自动配置"></a>因为springboot应用开启了自动配置</h5><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">@EnableAutoConfiguration   //是一个注解  注解也可以用一些作用</span><br></pre></td></tr></table></figure>

<h5 id="而-EnableAutoConfiguration自动配置通过一个类来批量导入组件"><a href="#而-EnableAutoConfiguration自动配置通过一个类来批量导入组件" class="headerlink" title="而@EnableAutoConfiguration自动配置通过一个类来批量导入组件"></a>而@EnableAutoConfiguration自动配置通过一个类来批量导入组件</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//通过引入AutoConfigurationImportSelector 来实现批量导入</span></span><br><span class="line"><span class="meta">@Import(AutoConfigurationImportSelector.class)</span></span><br><span class="line"><span class="keyword">public</span> <span class="meta">@interface</span> EnableAutoConfiguration &#123;</span><br><span class="line">	<span class="type">String</span> <span class="variable">ENABLED_OVERRIDE_PROPERTY</span> <span class="operator">=</span> </span><br><span class="line">	Class&lt;?&gt;[] exclude() <span class="keyword">default</span> &#123;&#125;;</span><br><span class="line">	String[] excludeName() <span class="keyword">default</span> &#123;&#125;;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h5 id="加载-META-INF-spring-org-springframework-boot-autoconfigure-AutoConfiguration-imports-文件中配置的所有组件"><a href="#加载-META-INF-spring-org-springframework-boot-autoconfigure-AutoConfiguration-imports-文件中配置的所有组件" class="headerlink" title="加载 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件中配置的所有组件"></a>加载 <code>META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports</code> 文件中配置的所有组件</h5><h2 id="MvcConfigurer"><a href="#MvcConfigurer" class="headerlink" title="MvcConfigurer"></a>MvcConfigurer</h2><h3 id="整合所有适配器"><a href="#整合所有适配器" class="headerlink" title="整合所有适配器"></a>整合所有适配器</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//Mvc配置器</span></span><br><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MyConfigurer</span> <span class="keyword">implements</span> <span class="title class_">WebMvcConfigurer</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//处理静态资源规则</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">addResourceHandlers</span><span class="params">(ResourceHandlerRegistry registry)</span> &#123;</span><br><span class="line">        WebMvcConfigurer.<span class="built_in">super</span>.addResourceHandlers(registry);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//添加拦截器</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">addInterceptors</span><span class="params">(InterceptorRegistry registry)</span> &#123;</span><br><span class="line">        registry.addInterceptor(<span class="keyword">new</span> <span class="title class_">MyInterceptor</span>())</span><br><span class="line">                <span class="comment">//拦截的路径  和  不拦截的路径</span></span><br><span class="line">                .addPathPatterns(<span class="string">&quot;/**&quot;</span>).excludePathPatterns(<span class="string">&quot;/public/**&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">//用于扩展消息转换器。通过该方法，您可以注册自定义的HttpMessageConverter，用于处理请求和响应的消息转换。</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">extendMessageConverters</span><span class="params">(List&lt;HttpMessageConverter&lt;?&gt;&gt; converters)</span> &#123;</span><br><span class="line">		<span class="comment">// 创建自定义的JSON消息转换器</span></span><br><span class="line">        <span class="type">MappingJackson2HttpMessageConverter</span> <span class="variable">customConverter</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">MappingJackson2HttpMessageConverter</span>();</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 设置自定义的ObjectMapper，这里只是举例，您可以根据需求进行配置</span></span><br><span class="line">        <span class="type">ObjectMapper</span> <span class="variable">customObjectMapper</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectMapper</span>(<span class="keyword">new</span> <span class="title class_">JsonFactory</span>());</span><br><span class="line">        <span class="comment">// 在这里可以对ObjectMapper进行定制，比如设置日期格式、忽略空值等</span></span><br><span class="line">        <span class="comment">// customObjectMapper.setDateFormat(new SimpleDateFormat(&quot;yyyy-MM-dd&quot;));</span></span><br><span class="line"></span><br><span class="line">        customConverter.setObjectMapper(customObjectMapper);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 将自定义的消息转换器添加到转换器列表中</span></span><br><span class="line">        converters.add(customConverter);</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//用于配置消息转换器。通过该方法，您可以配置Spring MVC的消息转换器，例如设置默认的消息转换器、添加自定义的消息转换器等。</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">configureMessageConverters</span><span class="params">(List&lt;HttpMessageConverter&lt;?&gt;&gt; converters)</span> &#123;</span><br><span class="line">		</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//用于添加自定义的方法参数解析器。通过该方法，您可以注册自定义的方法参数解析器，用于解析控制器方法的参数</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">addArgumentResolvers</span><span class="params">(List&lt;HandlerMethodArgumentResolver&gt; resolvers)</span> &#123;</span><br><span class="line">        <span class="comment">//resolvers.add(new CustomArgumentResolver()); 可以添加自己的参数解析器</span></span><br><span class="line">        </span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">	<span class="comment">//用于配置内容协商策略。通过该方法，您可以设置内容协商的行为，例如设置默认的媒体类型、参数、路径扩展等。以及服务器自身的特性，动态地		确定返回的响应内容</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">configureContentNegotiation</span><span class="params">(ContentNegotiationConfigurer configurer)</span> &#123;</span><br><span class="line">		configurer</span><br><span class="line">            .favorPathExtension(<span class="literal">true</span>)  <span class="comment">// 启用路径扩展</span></span><br><span class="line">            .ignoreAcceptHeader(<span class="literal">false</span>) <span class="comment">// 忽略Accept头部</span></span><br><span class="line">            .defaultContentType(MediaType.APPLICATION_JSON); <span class="comment">// 默认返回JSON</span></span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">//设置跨域</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">addCorsMappings</span><span class="params">(CorsRegistry registry)</span> &#123;</span><br><span class="line">		</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//允许您注册自定义的格式化器（Formatter）和转换器（Converter）</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">addFormatters</span><span class="params">(FormatterRegistry registry)</span> &#123;</span><br><span class="line">        <span class="comment">//可以使用addFormatters方法注册自定义的格式化器和转换器</span></span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//用于添加自定义的返回值处理器。通过该方法，您可以注册自定义的返回值处理器，用于处理控制器方法的返回值。</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">addReturnValueHandlers</span><span class="params">(List&lt;HandlerMethodReturnValueHandler&gt; handlers)</span> &#123;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//可以映射到某些静态页面的处理器</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">addViewControllers</span><span class="params">(ViewControllerRegistry registry)</span> &#123;</span><br><span class="line">		registry.addViewController(<span class="string">&quot;/welcome&quot;</span>).setViewName(<span class="string">&quot;welcome&quot;</span>);</span><br><span class="line">        registry.addViewController(<span class="string">&quot;/about&quot;</span>).setViewName(<span class="string">&quot;about&quot;</span>);</span><br><span class="line">		<span class="comment">//通过 addViewControllers 方法将路径 &quot;/welcome&quot; 映射到视图 &quot;welcome&quot;，将路径 &quot;/about&quot; 映射到视图 &quot;about&quot;</span></span><br><span class="line">        <span class="comment">//当用户访问我们的应用程序的 &quot;/welcome&quot; 路径时，Spring MVC 将会自动渲染 welcome.html 页面；当用户访问 &quot;/about&quot; 路径时，		将会自动渲染 about.html 页面</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">   </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>





<h2 id="拦截器-过滤器"><a href="#拦截器-过滤器" class="headerlink" title="拦截器 过滤器"></a>拦截器 过滤器</h2><p><strong>理解</strong></p>
<p>假设你在开发一个电子商务网站，有一个需求是在用户访问购物车页面时，需要进行两项操作：一是检查用户是否登录，未登录则跳转到登录页面；二是在购物车页面加载前，需要从数据库中加载用户的购物车信息。我们可以使用拦截器和过滤器来完成这两项操作。</p>
<h3 id="1-使用拦截器："><a href="#1-使用拦截器：" class="headerlink" title="1. 使用拦截器："></a>1. 使用拦截器：</h3><h4 id="拦截器的角色："><a href="#拦截器的角色：" class="headerlink" title="拦截器的角色："></a>拦截器的角色：</h4><ul>
<li><strong>登录检查：</strong> 在用户访问购物车页面之前，拦截器可以检查用户是否已登录，如果未登录，则跳转到登录页面。</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">LoginInterceptor</span> <span class="keyword">implements</span> <span class="title class_">HandlerInterceptor</span> &#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">preHandle</span><span class="params">(HttpServletRequest request, HttpServletResponse response, Object handler)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        <span class="comment">// 在请求处理之前进行拦截</span></span><br><span class="line">        <span class="type">HttpSession</span> <span class="variable">session</span> <span class="operator">=</span> request.getSession();</span><br><span class="line">        <span class="type">Object</span> <span class="variable">user</span> <span class="operator">=</span> session.getAttribute(<span class="string">&quot;user&quot;</span>);</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">if</span> (user == <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="comment">// 用户未登录，重定向到登录页面</span></span><br><span class="line">            response.sendRedirect(<span class="string">&quot;/login&quot;</span>);</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">false</span>; <span class="comment">// 请求中断</span></span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> <span class="literal">true</span>; <span class="comment">// 请求继续</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 其他方法实现略</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="注册拦截器："><a href="#注册拦截器：" class="headerlink" title="注册拦截器："></a>注册拦截器：</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">WebConfig</span> <span class="keyword">implements</span> <span class="title class_">WebMvcConfigurer</span> &#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">addInterceptors</span><span class="params">(InterceptorRegistry registry)</span> &#123;</span><br><span class="line">        registry.addInterceptor(<span class="keyword">new</span> <span class="title class_">LoginInterceptor</span>()).addPathPatterns(<span class="string">&quot;/cart&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="2-使用过滤器："><a href="#2-使用过滤器：" class="headerlink" title="2. 使用过滤器："></a>2. 使用过滤器：</h3><h4 id="过滤器的角色："><a href="#过滤器的角色：" class="headerlink" title="过滤器的角色："></a>过滤器的角色：</h4><ul>
<li><strong>购物车信息加载：</strong> 在用户访问购物车页面之前，过滤器可以从数据库加载用户的购物车信息，并将其放入请求的属性中。</li>
</ul>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">javaCopy codepublic class CartFilter implements Filter &#123;</span><br><span class="line">    @Override</span><br><span class="line">    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException &#123;</span><br><span class="line">        // 在请求处理之前进行过滤</span><br><span class="line">        HttpServletRequest httpRequest = (HttpServletRequest) request;</span><br><span class="line">        HttpSession session = httpRequest.getSession();</span><br><span class="line">        Object user = session.getAttribute(&quot;user&quot;);</span><br><span class="line">        </span><br><span class="line">        if (user != null) &#123;</span><br><span class="line">            // 用户已登录，加载购物车信息并放入请求属性</span><br><span class="line">            ShoppingCart cart = cartService.loadCart((User) user);</span><br><span class="line">            request.setAttribute(&quot;cart&quot;, cart);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        chain.doFilter(request, response); // 请求继续</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    // 其他方法实现略</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="注册过滤器："><a href="#注册过滤器：" class="headerlink" title="注册过滤器："></a>注册过滤器：</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">javaCopy code@Configuration</span><br><span class="line">public class WebConfig &#123;</span><br><span class="line">    @Bean</span><br><span class="line">    public FilterRegistrationBean&lt;CartFilter&gt; cartFilter() &#123;</span><br><span class="line">        FilterRegistrationBean&lt;CartFilter&gt; registrationBean = new FilterRegistrationBean&lt;&gt;();</span><br><span class="line">        registrationBean.setFilter(new CartFilter());</span><br><span class="line">        registrationBean.addUrlPatterns(&quot;/cart&quot;);</span><br><span class="line">        return registrationBean;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="总结："><a href="#总结：" class="headerlink" title="总结："></a>总结：</h3><ul>
<li>使用拦截器进行登录检查，确保用户已登录。</li>
<li>使用过滤器加载购物车信息，确保购物车信息在请求到达控制器之前被加载。</li>
</ul>
<p>这样，通过拦截器和过滤器的协同作用，我们可以在用户访问购物车页面时完成多个步骤的处理，分别处理与登录状态检查和购物车信息加载相关的逻辑。</p>
<h3 id="自定义-过滤器-拦截器"><a href="#自定义-过滤器-拦截器" class="headerlink" title="自定义 过滤器,拦截器"></a>自定义 过滤器,拦截器</h3><p>过滤器是在项目启动时就会初始化，先通过过滤器 过滤器逻辑处理完， 再执行拦截器 并且过滤器是项目结束后销毁 拦截器只处理一次请求</p>
<h4 id="过滤器"><a href="#过滤器" class="headerlink" title="过滤器"></a>过滤器</h4><h5 id="首先通过servlet的api来写一个过滤器"><a href="#首先通过servlet的api来写一个过滤器" class="headerlink" title="首先通过servlet的api来写一个过滤器"></a>首先通过servlet的api来写一个过滤器</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//拦截所有</span></span><br><span class="line"><span class="meta">@WebFilter(&quot;/*&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MyFilter</span> <span class="keyword">implements</span> <span class="title class_">Filter</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">init</span><span class="params">(FilterConfig filterConfig)</span> <span class="keyword">throws</span> ServletException 	&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;过滤器加载成功&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">doFilter</span><span class="params">(ServletRequest servletRequest, ServletResponse 	servletResponse, FilterChain filterChain)</span> <span class="keyword">throws</span> IOException, 		ServletException &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;你好这是过滤器的内容&quot;</span>);</span><br><span class="line">        filterChain.doFilter(servletRequest,servletResponse);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">destroy</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;过滤器销毁了&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h5 id="然后交给springboot管理-这时候-过滤器自动生效"><a href="#然后交给springboot管理-这时候-过滤器自动生效" class="headerlink" title="然后交给springboot管理 这时候 过滤器自动生效"></a>然后交给springboot管理 这时候 过滤器自动生效</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">filterConfig</span> &#123;</span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="keyword">public</span> FilterRegistrationBean&lt;MyFilter&gt; <span class="title function_">myFilter</span><span class="params">()</span>&#123;</span><br><span class="line">        <span class="comment">//创建过滤器注册对象</span></span><br><span class="line">        FilterRegistrationBean&lt;MyFilter&gt; myFilterFilterRegistrationBean = <span class="keyword">new</span> <span class="title class_">FilterRegistrationBean</span>&lt;&gt;();</span><br><span class="line">        <span class="comment">//设置filter</span></span><br><span class="line">        myFilterFilterRegistrationBean.setFilter(<span class="keyword">new</span> <span class="title class_">MyFilter</span>());</span><br><span class="line">        <span class="comment">//设置匹配位置</span></span><br><span class="line">        myFilterFilterRegistrationBean.addUrlPatterns(<span class="string">&quot;/*&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> myFilterFilterRegistrationBean;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<h4 id="拦截器"><a href="#拦截器" class="headerlink" title="拦截器"></a>拦截器</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MyInterceptor</span> <span class="keyword">implements</span> <span class="title class_">HandlerInterceptor</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">MyInterceptor</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="built_in">super</span>();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">preHandle</span><span class="params">(HttpServletRequest request, HttpServletResponse response, Object handler)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        <span class="comment">// 在处理程序执行前执行的逻辑</span></span><br><span class="line">        System.out.println(<span class="string">&quot;拦截器准备&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> HandlerInterceptor.<span class="built_in">super</span>.preHandle(request, response, handler);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">postHandle</span><span class="params">(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        <span class="comment">// 在处理程序执行后但未渲染视图时执行的逻辑</span></span><br><span class="line">        System.out.println(<span class="string">&quot;拦截器执行中&quot;</span>);</span><br><span class="line">        HandlerInterceptor.<span class="built_in">super</span>.postHandle(request, response, handler, modelAndView);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">afterCompletion</span><span class="params">(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        <span class="comment">// 在完成请求处理后执行的逻辑</span></span><br><span class="line">        System.out.println(<span class="string">&quot;拦截器完美落幕&quot;</span>);</span><br><span class="line">        HandlerInterceptor.<span class="built_in">super</span>.afterCompletion(request, response, handler, ex);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h5 id="然后在MvcConfig添加"><a href="#然后在MvcConfig添加" class="headerlink" title="然后在MvcConfig添加"></a>然后在MvcConfig添加</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//Mvc配置器</span></span><br><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MyConfigurer</span> <span class="keyword">implements</span> <span class="title class_">WebMvcConfigurer</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//处理静态资源规则</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">addResourceHandlers</span><span class="params">(ResourceHandlerRegistry registry)</span> &#123;</span><br><span class="line">        WebMvcConfigurer.<span class="built_in">super</span>.addResourceHandlers(registry);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//添加拦截器</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">addInterceptors</span><span class="params">(InterceptorRegistry registry)</span> &#123;</span><br><span class="line">        registry.addInterceptor(<span class="keyword">new</span> <span class="title class_">MyInterceptor</span>())</span><br><span class="line">                <span class="comment">//拦截的路径  和  不拦截的路径</span></span><br><span class="line">                .addPathPatterns(<span class="string">&quot;/**&quot;</span>).excludePathPatterns(<span class="string">&quot;/public/**&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>









<h2 id="日期格式化转换器"><a href="#日期格式化转换器" class="headerlink" title="日期格式化转换器"></a>日期格式化转换器</h2><h5 id="首先，创建自定义的日期格式化器："><a href="#首先，创建自定义的日期格式化器：" class="headerlink" title="首先，创建自定义的日期格式化器："></a>首先，创建自定义的日期格式化器：</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">CustomDateFormatter</span> <span class="keyword">implements</span> <span class="title class_">Formatter</span>&lt;Date&gt; &#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//自定义的格式</span></span><br><span class="line">    <span class="keyword">private</span> String formatPattern;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">CustomDateFormatter</span><span class="params">(String formatPattern)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.formatPattern = formatPattern;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//locale是地区 用于指定时区</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">print</span><span class="params">(Date object, Locale locale)</span> &#123;</span><br><span class="line">        <span class="comment">//这个对象用于指定日期的规则 例如yyyy-MM-dd HH:mm:ss</span></span><br><span class="line">        <span class="type">SimpleDateFormat</span> <span class="variable">sdf</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">SimpleDateFormat</span>(formatPattern);</span><br><span class="line">        <span class="keyword">return</span> sdf.format(object);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> Date <span class="title function_">parse</span><span class="params">(String text, Locale locale)</span> <span class="keyword">throws</span> ParseException &#123;</span><br><span class="line">        <span class="type">SimpleDateFormat</span> <span class="variable">sdf</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">SimpleDateFormat</span>(formatPattern);</span><br><span class="line">        <span class="keyword">return</span> sdf.parse(text);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<h5 id="然后，创建自定义的string-obj转换器"><a href="#然后，创建自定义的string-obj转换器" class="headerlink" title="然后，创建自定义的string-obj转换器"></a>然后，创建自定义的string-obj转换器</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">CustomStringToUserConverter</span> <span class="keyword">implements</span> <span class="title class_">Converter</span>&lt;String, User&gt; &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> User <span class="title function_">convert</span><span class="params">(String source)</span> &#123;</span><br><span class="line">        <span class="comment">// 输入的字符串转成java对象</span></span><br><span class="line">        <span class="type">User</span> <span class="variable">user</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">User</span>();</span><br><span class="line">        user.setUsername(source);</span><br><span class="line">        <span class="keyword">return</span> user;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<h5 id="在WebConfig-通过addFormatters方法注册这些自定义的格式化器和转换器"><a href="#在WebConfig-通过addFormatters方法注册这些自定义的格式化器和转换器" class="headerlink" title="在WebConfig 通过addFormatters方法注册这些自定义的格式化器和转换器"></a>在WebConfig 通过addFormatters方法注册这些自定义的格式化器和转换器</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="meta">@EnableWebMvc</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">WebConfig</span> <span class="keyword">implements</span> <span class="title class_">WebMvcConfigurer</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">addFormatters</span><span class="params">(FormatterRegistry registry)</span> &#123;</span><br><span class="line">        registry.addFormatter(<span class="keyword">new</span> <span class="title class_">CustomDateFormatter</span>(<span class="string">&quot;yyyy-MM-dd&quot;</span>));</span><br><span class="line">        registry.addConverter(<span class="keyword">new</span> <span class="title class_">CustomStringToUserConverter</span>());</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>



<h2 id="参数解析器"><a href="#参数解析器" class="headerlink" title="参数解析器"></a>参数解析器</h2><p>假设您正在开发一个电子商务网站，您希望用户在下订单时能够使用优惠码。您可以创建一个自定义的方法参数解析器来处理这个优惠码，以便在控制器方法中轻松地获取并使用该优惠码</p>
<p>首先，创建一个名为 <code>Coupon</code> 的自定义类来表示优惠码</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Coupon</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> String code;</span><br><span class="line">    <span class="comment">// 可能还有其他优惠码相关的属性和方法</span></span><br><span class="line">    <span class="comment">// ...</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 省略 getter 和 setter 方法</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>接下来，创建一个自定义的方法参数解析器 <code>CouponArgumentResolver</code>，用于解析请求中的优惠码并将其转换为 <code>Coupon</code> 对象</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//子集实现的方法参数解析器		</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">CouponArgumentResolver</span> <span class="keyword">implements</span> <span class="title class_">HandlerMethodArgumentResolver</span> &#123;</span><br><span class="line">        </span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">supportsParameter</span><span class="params">(MethodParameter parameter)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> parameter.getParameterType().equals(Coupon.class);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> Object <span class="title function_">resolveArgument</span><span class="params">(MethodParameter parameter, ModelAndViewContainer mavContainer, </span></span><br><span class="line"><span class="params">                                  NativeWebRequest webRequest, WebDataBinderFactory binderFactory)</span> <span class="keyword">throws</span> Exception 	&#123;</span><br><span class="line">        <span class="comment">//从请求中获取名为 &quot;couponCode&quot; 的参数值的代码</span></span><br><span class="line">        <span class="type">String</span> <span class="variable">couponCode</span> <span class="operator">=</span> webRequest.getParameter(<span class="string">&quot;couponCode&quot;</span>);</span><br><span class="line">        <span class="type">Coupon</span> <span class="variable">coupon</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Coupon</span>();</span><br><span class="line">        coupon.setCode(couponCode);</span><br><span class="line">        <span class="comment">//这个 Coupon 对象将被返回，作为控制器方法的参数传递给处理订单的逻辑</span></span><br><span class="line">        <span class="keyword">return</span> coupon;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>然后，将自定义的方法参数解析器注册到Spring框架中，让它生效</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="meta">@EnableWebMvc</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">WebConfig</span> <span class="keyword">implements</span> <span class="title class_">WebMvcConfigurer</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">addArgumentResolvers</span><span class="params">(List&lt;HandlerMethodArgumentResolver&gt; resolvers)</span> &#123;</span><br><span class="line">        resolvers.add(<span class="keyword">new</span> <span class="title class_">CouponArgumentResolver</span>());</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>最后，在控制器方法中直接声明 <code>Coupon</code> 类型的参数,并且我们可以通过这个对象获取到优惠码，并让Spring框架自动使用自定义的方法参数解析器来处理优惠码：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@RequestMapping(&quot;/orders&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">OrderController</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@PostMapping(&quot;/create&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">createOrder</span><span class="params">(<span class="meta">@RequestParam(&quot;productId&quot;)</span> String productId, <span class="meta">@RequestParam(&quot;quantity&quot;)</span> <span class="type">int</span> quantity, 	Coupon coupon)</span> &#123;</span><br><span class="line">        <span class="comment">// 在这里可以直接使用Coupon对象，而不需要手动解析优惠码</span></span><br><span class="line">        <span class="comment">// 处理订单逻辑，包括使用优惠码等</span></span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;Order created successfully&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>



<h2 id="AOP"><a href="#AOP" class="headerlink" title="AOP"></a>AOP</h2><h5 id="首先导入aop依赖"><a href="#首先导入aop依赖" class="headerlink" title="首先导入aop依赖"></a>首先导入aop依赖</h5><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">       <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">       <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-aop<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<h5 id="触发顺序"><a href="#触发顺序" class="headerlink" title="触发顺序"></a>触发顺序</h5><p>你好这是过滤器的内容</p>
<p>hello 之前触发的方法</p>
<p>hello 之后触发的方法</p>
<h5 id="首先确定切点对象-Hellocontroller-然后编写aop"><a href="#首先确定切点对象-Hellocontroller-然后编写aop" class="headerlink" title="首先确定切点对象 Hellocontroller 然后编写aop"></a>首先确定切点对象 Hellocontroller 然后编写aop</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Aspect</span></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">HelloAspect</span> &#123;</span><br><span class="line">    <span class="comment">//切点</span></span><br><span class="line">    <span class="meta">@Pointcut(&quot;execution(* MainApplication.controller.HelloController.*(..))&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">BeforeHelloController</span><span class="params">()</span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;hahahaha&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="meta">@Before(&quot;BeforeHelloController()&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">LogBeforeHello</span><span class="params">()</span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;hello 之前触发的方法&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="meta">@After(&quot;BeforeHelloController()&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">LogAfterHello</span><span class="params">()</span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;hello 之后触发的方法&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>





<h2 id="自定义注解"><a href="#自定义注解" class="headerlink" title="自定义注解"></a>自定义注解</h2><p>首先编写一个注解 保留策略为运行时 指定了这个注解可以用在方法和类和字段上，通过<code>@Target</code>注解指定</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Retention(RetentionPolicy.RUNTIME)</span></span><br><span class="line"><span class="meta">@Target(&#123;ElementType.FIELD,ElementType.TYPE,ElementType.METHOD&#125;)</span></span><br><span class="line"><span class="meta">@Documented</span></span><br><span class="line"><span class="keyword">public</span> <span class="meta">@interface</span> Test &#123;</span><br><span class="line">    <span class="comment">//注解中想要标注的信息  并且default 为空</span></span><br><span class="line">    String <span class="title function_">name</span><span class="params">()</span> <span class="keyword">default</span> <span class="string">&quot;默认值&quot;</span>;</span><br><span class="line">    <span class="type">int</span> <span class="title function_">count</span><span class="params">()</span> <span class="keyword">default</span> <span class="number">1</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>一旦定义了自定义注解，你可以在代码中使用它。例如，在一个类或方法上使用<code>Test</code>注解</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Test(name = &quot;name&quot;, count = 1)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Pig</span> &#123;</span><br><span class="line">    <span class="meta">@Test(count = 3)</span></span><br><span class="line">    <span class="keyword">private</span> String name;</span><br><span class="line">    <span class="keyword">private</span> Integer age;</span><br><span class="line">    <span class="meta">@Test(count = 1)</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setName</span><span class="params">(String name)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.name = name;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>使用反射来读取和处理自定义注解</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">Class&lt;Pig&gt; pigClass = Pig.class;</span><br><span class="line">      <span class="type">Test</span> <span class="variable">annotation</span> <span class="operator">=</span> pigClass.getAnnotation(Test.class);</span><br><span class="line">      System.out.println(annotation.count());</span><br><span class="line">      System.out.println(annotation.name());	</span><br></pre></td></tr></table></figure>





<h2 id="国际化配置"><a href="#国际化配置" class="headerlink" title="国际化配置"></a>国际化配置</h2><h3 id="MessageSource"><a href="#MessageSource" class="headerlink" title="MessageSource"></a><code>MessageSource</code></h3><p><strong>定义消息资源文件</strong></p>
<p>分别定义三个对于三个国际的语言标准: message.properties   message_for_en.properties….</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">greeting=Hello</span><br><span class="line">greeting=Bonjour</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>**配置Spring Boot应用 **application.properties</p>
<p>例如: message_zh_CN.properties</p>
<p>message_zh_CN.properties</p>
<h5 id="这样做会告诉Spring-Boot去查找名为messages-properties的消息资源文件，并且如果找不到对应的消息，就会回退到系统的默认语言。"><a href="#这样做会告诉Spring-Boot去查找名为messages-properties的消息资源文件，并且如果找不到对应的消息，就会回退到系统的默认语言。" class="headerlink" title="这样做会告诉Spring Boot去查找名为messages.properties的消息资源文件，并且如果找不到对应的消息，就会回退到系统的默认语言。"></a>这样做会告诉Spring Boot去查找名为<code>messages.properties</code>的消息资源文件，并且如果找不到对应的消息，就会回退到系统的默认语言。</h5><figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#配置国际化</span></span><br><span class="line"><span class="attr">spring.messages.basename</span>=<span class="string">messages</span></span><br><span class="line"><span class="attr">spring.messages.fallback-to-system-locale</span>=<span class="string">true</span></span><br><span class="line"></span><br></pre></td></tr></table></figure>

<h5 id="在类中使用"><a href="#在类中使用" class="headerlink" title="在类中使用"></a>在类中使用</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">HelloController</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> MessageSource messageSource;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">HelloController</span><span class="params">(MessageSource messageSource)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.messageSource = messageSource;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="meta">@GetMapping(&quot;/hello&quot;)</span></span><br><span class="line">    <span class="meta">@ResponseBody</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">hello</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> messageSource.getMessage(<span class="string">&quot;greeting&quot;</span>,<span class="literal">null</span>, LocaleContextHolder.getLocale());</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h5 id="controller使用"><a href="#controller使用" class="headerlink" title="controller使用"></a>controller使用</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">HelloController</span> &#123;</span><br><span class="line">	<span class="comment">//注入国际化组件 从ioc中</span></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    MessageSource messageSource;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@GetMapping(&quot;/hello1&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">hello1</span><span class="params">(HttpServletRequest request)</span> &#123;</span><br><span class="line">        <span class="comment">//从请求对象中获取该用户的地区</span></span><br><span class="line">        <span class="type">Locale</span> <span class="variable">locale</span> <span class="operator">=</span> request.getLocale();</span><br><span class="line">        <span class="comment">//根据地区来配置显示内容</span></span><br><span class="line">        <span class="keyword">return</span> messageSource.getMessage(<span class="string">&quot;greeting&quot;</span>, <span class="literal">null</span>, locale);</span><br><span class="line">    &#125;&#125;</span><br></pre></td></tr></table></figure>



<h2 id="Http缓存"><a href="#Http缓存" class="headerlink" title="Http缓存"></a>Http缓存</h2><h5 id="配置缓存配置"><a href="#配置缓存配置" class="headerlink" title="配置缓存配置"></a>配置缓存配置</h5><figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#开启静态资源映射规则</span></span><br><span class="line"><span class="attr">spring.web.resources.add-mappings</span>=<span class="string">true</span></span><br><span class="line"><span class="comment">#设置缓存 缓存一小时</span></span><br><span class="line"><span class="attr">spring.web.resources.cache.period</span>=<span class="string">3600s</span></span><br><span class="line"><span class="comment">#缓存设置中心 并且会覆盖上面的period配置</span></span><br><span class="line"><span class="attr">spring.web.resources.cache.cachecontrol.max-age</span>=<span class="string">7200s</span></span><br><span class="line"><span class="comment">#使用资源 last时间来对比</span></span><br><span class="line"><span class="attr">spring.web.resources.cache.use-last-modified</span>=<span class="string">true</span></span><br></pre></td></tr></table></figure>







<h2 id="适配多种数据返回"><a href="#适配多种数据返回" class="headerlink" title="适配多种数据返回"></a>适配多种数据返回</h2><p>例如 写好了一个接口 移动端和网页端访问希望返回一个json 第三方希望返回一个xml ….</p>
<h3 id="1-默认适配json"><a href="#1-默认适配json" class="headerlink" title="1.默认适配json"></a>1.默认适配json</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//默认支持把对象写为json 因为web场景默认导入了jackson处理json的包</span></span><br><span class="line">    <span class="meta">@GetMapping(&quot;/hello&quot;)</span></span><br><span class="line">    <span class="meta">@ResponseBody</span> <span class="comment">//带有这个 所有都默认返回json</span></span><br><span class="line">    <span class="keyword">public</span> Pig <span class="title function_">hello</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Pig</span>(<span class="string">&quot;张明&quot;</span>,<span class="number">18</span>);</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>

<p>json 转 xml通过依赖和注解类</p>
<p>通过Jackson 先导入支持xml格式的依赖导入</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!--        jackson处理xml返回--&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.fasterxml.jackson.dataformat<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>jackson-dataformat-xml<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>标注注解在返回类上</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@JacksonXmlRootElement</span> <span class="comment">//可以写出为xml文档</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Pig</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> String name;</span><br><span class="line">    <span class="keyword">private</span> Integer age;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>浏览器默认accpet 的 txt优先级最高 所以显示文本</p>
<h3 id="2-通过请求参数"><a href="#2-通过请求参数" class="headerlink" title="2.通过请求参数"></a>2.通过请求参数</h3><p>配置下面:</p>
<figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">spring.mvc.contentnegotiation.favor-parameter</span>=<span class="string">true</span></span><br></pre></td></tr></table></figure>







<h2 id="校验器"><a href="#校验器" class="headerlink" title="校验器"></a>校验器</h2><p><strong>Vaildator</strong></p>
<h3 id="默认校验器"><a href="#默认校验器" class="headerlink" title="默认校验器"></a>默认校验器</h3><p><strong>首先导入依赖</strong></p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-validation<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span>	</span><br></pre></td></tr></table></figure>

<p><strong>然后就可以在实体类中使用</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Pig</span> &#123;</span><br><span class="line">    <span class="meta">@NotNull</span></span><br><span class="line">    <span class="keyword">private</span> String name;</span><br><span class="line">    <span class="meta">@NotNull</span></span><br><span class="line">    <span class="keyword">private</span> Integer age;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>然后在控制层加校验器</strong>@Valid</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@PostMapping(&quot;/hello&quot;)</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">hello</span><span class="params">(<span class="meta">@Valid</span> Pig pig)</span> &#123;</span><br><span class="line">        System.out.println(pig);</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>

<p><strong>如果校验失败 会给前端返回一个异常 MethodArgumentNotValidException</strong></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Validation error: Validation failed for argument [0] in public void MainApplication.controller.HelloController.hello(MainApplication.pojo.Pig): [Field error in object &#x27;pig&#x27; on field &#x27;name&#x27;: rejected value [hsaha]; codes [Prefix.pig.name,Prefix.name,Prefix.java.lang.String,Prefix]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [pig.name,name]; arguments []; default message [name],123]; default message [?????????]] </span><br></pre></td></tr></table></figure>

<p><strong>也可以自己捕获后将错误信息 通过全局异常处理器 返回给前端</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@ControllerAdvice</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">GlobalExceptionHandler</span> &#123;</span><br><span class="line">    <span class="meta">@ExceptionHandler(MethodArgumentNotValidException.class)</span></span><br><span class="line">    <span class="meta">@ResponseStatus(HttpStatus.BAD_REQUEST)</span></span><br><span class="line">    <span class="keyword">public</span> ResponseEntity&lt;String&gt; <span class="title function_">handleValidationException</span><span class="params">(MethodArgumentNotValidException ex)</span> &#123;</span><br><span class="line">        <span class="comment">// 处理验证错误</span></span><br><span class="line">        <span class="keyword">return</span> ResponseEntity.badRequest().body(<span class="string">&quot;Validation error: &quot;</span> + ex.getMessage());</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>





<h3 id="自定义校验规则"><a href="#自定义校验规则" class="headerlink" title="自定义校验规则"></a>自定义校验规则</h3><p><strong>步骤一：创建自定义注解</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Target(&#123; ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER &#125;)</span> <span class="comment">//可以作用在字段 方法 参数上</span></span><br><span class="line"><span class="meta">@Retention(RetentionPolicy.RUNTIME)</span>  <span class="comment">//指定在编译时</span></span><br><span class="line"><span class="meta">@Constraint(validatedBy = PrefixValidator.class)</span> <span class="comment">//校验器元注解</span></span><br><span class="line"><span class="keyword">public</span> <span class="meta">@interface</span> Prefix &#123;</span><br><span class="line">    <span class="comment">//这是参数 可以多可以少</span></span><br><span class="line">    String <span class="title function_">value</span><span class="params">()</span>;</span><br><span class="line">    <span class="comment">//这里是错误信息中返回的错误信息</span></span><br><span class="line">    String <span class="title function_">message</span><span class="params">()</span> <span class="keyword">default</span> <span class="string">&quot; &quot;</span>;</span><br><span class="line">    <span class="comment">//下面这俩直接copy</span></span><br><span class="line">    Class&lt;?&gt;[] groups() <span class="keyword">default</span> &#123;&#125;;</span><br><span class="line">    Class&lt;? <span class="keyword">extends</span> <span class="title class_">Payload</span>&gt;[] payload() <span class="keyword">default</span> &#123;&#125;;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>步骤二:创建一个校验器类</strong></p>
<p>实现了 <code>ConstraintValidator&lt;Prefix, String&gt;</code> 接口，其中 <code>Prefix</code> 是我们定义的注解，<code>String</code> 是需要验证的字段类型。在 <code>isValid</code> 方法中，我们编写了自定义的校验逻辑，即验证字符串是否以指定的前缀开头</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//校验器类</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">PrefixValidator</span> <span class="keyword">implements</span> <span class="title class_">ConstraintValidator</span>&lt;Prefix, String&gt; &#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">initialize</span><span class="params">(Prefix constraintAnnotation)</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;校验器初始化完毕&quot;</span>);</span><br><span class="line">        ConstraintValidator.<span class="built_in">super</span>.initialize(constraintAnnotation);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">isValid</span><span class="params">(String s, ConstraintValidatorContext constraintValidatorContext)</span> &#123;</span><br><span class="line">        <span class="comment">//这里写校验器的逻辑</span></span><br><span class="line">        System.out.println(s+constraintValidatorContext.toString());</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>步骤三:实体类中使用注解</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Pig</span> &#123;</span><br><span class="line">    <span class="meta">@Prefix(&quot;123&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> String name;</span><br><span class="line">    <span class="meta">@NotNull</span></span><br><span class="line">    <span class="keyword">private</span> Integer age;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>步骤四:控制层使用</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@PostMapping(&quot;/hello&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">hello</span><span class="params">(<span class="meta">@Valid</span> Pig pig)</span> &#123;</span><br><span class="line">        System.out.println(pig);</span><br><span class="line">    &#125;	</span><br></pre></td></tr></table></figure>

<p><strong>这时候如果校验失败 会被全局异常处理器发现捕捉后返回错误</strong></p>
<h2 id="Jackson工具类"><a href="#Jackson工具类" class="headerlink" title="Jackson工具类"></a>Jackson工具类</h2><h3 id="处理JSON序列化和反序列化-以及yaml"><a href="#处理JSON序列化和反序列化-以及yaml" class="headerlink" title="处理JSON序列化和反序列化 以及yaml"></a>处理JSON序列化和反序列化 以及yaml</h3><p><code>ObjectMapper</code>可以将Java对象转换为JSON格式的字符串，也可以将JSON格式的字符串转换为Java对象。这使得在处理HTTP请求和响应时能够方便地将Java对象转换为JSON格式的数据，或者将接收到的JSON格式的数据转换为Java对象进行处理。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//java对象</span></span><br><span class="line"><span class="type">Pig</span> <span class="variable">pig</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Pig</span>(<span class="string">&quot;zhangsan&quot;</span>,<span class="number">18</span>);</span><br><span class="line"><span class="comment">//指定为yaml效力</span></span><br><span class="line"><span class="type">ObjectMapper</span> <span class="variable">mapper</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectMapper</span>(<span class="keyword">new</span> <span class="title class_">YAMLFactory</span>());</span><br><span class="line"></span><br><span class="line"><span class="comment">//创建mapper 并且指定为json效力	</span></span><br><span class="line"><span class="type">ObjectMapper</span> <span class="variable">mapper1</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectMapper</span>(<span class="keyword">new</span> <span class="title class_">JsonFactory</span>());</span><br><span class="line"></span><br><span class="line"><span class="comment">//转为json</span></span><br><span class="line">mapper1.writeValueAsString(pig)	</span><br></pre></td></tr></table></figure>

<p>也可以直接创建对应工厂对象</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//去掉---  也就是上面的横线 通过下面 直接创建YAML工厂</span></span><br><span class="line"><span class="keyword">new</span> <span class="title class_">YAMLFactory</span>().disable(YAMLGenerator.Feature.WRITE_DOC_START_MARKER);</span><br></pre></td></tr></table></figure>







<h2 id="处理消息转换器"><a href="#处理消息转换器" class="headerlink" title="处理消息转换器"></a>处理消息转换器</h2><p><strong>HttpMessageConverter</strong></p>
<p>以处理yaml为例</p>
<p>首先让spring支持返回yaml数据</p>
<figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">spring.mvc.contentnegotiation.media-types.yaml</span> = <span class="string">text/yaml</span></span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//处理HTTP请求和响应消息转换的抽象基类</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MyHttpMessageConverter</span> <span class="keyword">extends</span> <span class="title class_">AbstractHttpMessageConverter</span>&lt;Object&gt; &#123;</span><br><span class="line">    <span class="comment">//引入Jackson</span></span><br><span class="line">    <span class="keyword">private</span> ObjectMapper objectMapper;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//基本配置</span></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">MyHttpMessageConverter</span><span class="params">()</span>&#123;</span><br><span class="line">        <span class="comment">//必须写</span></span><br><span class="line">        <span class="comment">//告诉springboot媒体类型 也就是 是yaml还是json  并且指定编码类型  </span></span><br><span class="line">        <span class="built_in">super</span>(<span class="keyword">new</span> <span class="title class_">MediaType</span>(<span class="string">&quot;text&quot;</span>,<span class="string">&quot;yaml&quot;</span>, StandardCharsets.UTF_8));</span><br><span class="line">        <span class="comment">//生成yaml工厂 </span></span><br><span class="line">        <span class="type">YAMLFactory</span> <span class="variable">factory</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">YAMLFactory</span>().disable(YAMLGenerator.Feature.WRITE_DOC_START_MARKER);</span><br><span class="line">        <span class="comment">//根据yaml工厂配置mapper</span></span><br><span class="line">        <span class="built_in">this</span>.objectMapper = <span class="keyword">new</span> <span class="title class_">ObjectMapper</span>(factory);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">//从请求消息中读取数据并将其转换为指定的Java对象 @RequestBody</span></span><br><span class="line">    <span class="comment">//clazz 要转换的Java类型</span></span><br><span class="line">    <span class="comment">//http... HTTP输入消息</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">protected</span> Object <span class="title function_">readInternal</span><span class="params">(Class&lt;?&gt; clazz, HttpInputMessage inputMessage)</span> <span class="keyword">throws</span> IOException, HttpMessageNotReadableException &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">null</span>;<span class="comment">//转换后的Java对象</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//将指定的Java对象写入到响应消息中   @ResponseBody</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">writeInternal</span><span class="params">(Object o, HttpOutputMessage outputMessage)</span> <span class="keyword">throws</span> IOException, HttpMessageNotWritableException &#123;</span><br><span class="line">        <span class="comment">//HttpOutputMessage 是一个输出流 是面向前端的</span></span><br><span class="line">		<span class="type">OutputStream</span> <span class="variable">body</span> <span class="operator">=</span> outputMessage.getBody();</span><br><span class="line">        <span class="comment">//利用try来最后关闭输出流</span></span><br><span class="line">        <span class="keyword">try</span>&#123;</span><br><span class="line">            <span class="comment">//利用Jackson来处理数据</span></span><br><span class="line">            <span class="built_in">this</span>.objectMapper.writeValue(body,o);</span><br><span class="line">        &#125;<span class="keyword">catch</span> (Exception e)&#123;</span><br><span class="line">            System.out.println(e);</span><br><span class="line">        &#125;<span class="keyword">finally</span> &#123;</span><br><span class="line">            body.close();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//获取该消息转换器支持的媒体类型列表</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> List&lt;MediaType&gt; <span class="title function_">getSupportedMediaTypes</span><span class="params">(Class&lt;?&gt; clazz)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">super</span>.getSupportedMediaTypes(clazz);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>









<h2 id="全局异常处理器"><a href="#全局异常处理器" class="headerlink" title="全局异常处理器"></a>全局异常处理器</h2><p><strong>GlobalExceptionHandler</strong></p>
<p><strong>统一错误处理机制</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//与全局异常处理一同使用</span></span><br><span class="line"><span class="meta">@ControllerAdvice</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">GlobalExceptionHandler</span> &#123;</span><br><span class="line">    <span class="comment">//该注解表明全局异常处理器</span></span><br><span class="line">    <span class="meta">@ExceptionHandler(MethodArgumentNotValidException.class)</span></span><br><span class="line">    <span class="comment">//指定错误信息返回的类型</span></span><br><span class="line">    <span class="meta">@ResponseStatus(HttpStatus.BAD_REQUEST)</span></span><br><span class="line">    <span class="keyword">public</span> ResponseEntity&lt;String&gt; <span class="title function_">handleValidationException</span><span class="params">(MethodArgumentNotValidException ex)</span> &#123;</span><br><span class="line">        <span class="comment">// 处理验证错误</span></span><br><span class="line">        <span class="keyword">return</span> ResponseEntity.badRequest().body(<span class="string">&quot;Validation error: &quot;</span> + ex.getMessage());</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">//返回json ，里面包含了错误信息 前端可以根据这个错误信息做出判断</span></span><br><span class="line">    <span class="meta">@ResponseBody</span></span><br><span class="line">    <span class="meta">@ExceptionHandler(Exception.class)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">handleException</span><span class="params">(Exception e)</span> &#123;</span><br><span class="line">        System.out.println(e.toString());</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;错误信息为&quot;</span> + e.toString();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>





<h2 id="错误信息新的返回信息"><a href="#错误信息新的返回信息" class="headerlink" title="错误信息新的返回信息"></a>错误信息新的返回信息</h2><p>打开</p>
<figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">spring.mvc.problemdetails.enabled</span>=<span class="string">true</span></span><br></pre></td></tr></table></figure>

<p>然后当发生错误返回的json为:</p>
<figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;type&quot;</span><span class="punctuation">:</span> <span class="string">&quot;about:blank&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;title&quot;</span><span class="punctuation">:</span> <span class="string">&quot;Method Not Allowed&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;status&quot;</span><span class="punctuation">:</span> <span class="number">405</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;detail&quot;</span><span class="punctuation">:</span> <span class="string">&quot;Method &#x27;POST&#x27; is not supported.&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;instance&quot;</span><span class="punctuation">:</span> <span class="string">&quot;/hello&quot;</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure>











<h2 id="函数式Web处理方式"><a href="#函数式Web处理方式" class="headerlink" title="函数式Web处理方式"></a>函数式Web处理方式</h2><p>编写Web函数式配置类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//实现函数式web</span></span><br><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">WebFunctionConfig</span> &#123;</span><br><span class="line">    <span class="comment">//在这里注入我们写的handler 也可以在pigRoute的形参里写 那样会自动注入</span></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    pigBisHandler pigBisHandler;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//交给spring</span></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="keyword">public</span> RouterFunction&lt;ServerResponse&gt; <span class="title function_">pigRoute</span><span class="params">(<span class="comment">/*pigBisHandler pigBisHandler*/</span>)</span>&#123;</span><br><span class="line">        <span class="comment">// RouterFunction 定义路由信息 发什么请求 谁来处理</span></span><br><span class="line">        <span class="comment">//  RequestPredicate 定义请求  请求方式 GET PUT</span></span><br><span class="line">        <span class="comment">//  ServiceRequest  封装请求</span></span><br><span class="line">        <span class="comment">//  ServiceResponse 封装响应</span></span><br><span class="line">        <span class="keyword">return</span> RouterFunctions.route() <span class="comment">//开始定义路由</span></span><br><span class="line">                .GET(<span class="string">&quot;/hello2&quot;</span>, RequestPredicates.accept(MediaType.ALL), pigBisHandler::handlePig)</span><br><span class="line">                .build();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>业务处理器</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//业务处理器</span></span><br><span class="line"><span class="meta">@Service</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">pigBisHandler</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//业务方法</span></span><br><span class="line">    <span class="keyword">public</span> ServerResponse <span class="title function_">handlePig</span><span class="params">(ServerRequest request)</span> <span class="keyword">throws</span> Exception&#123;</span><br><span class="line">        <span class="comment">//构造相应</span></span><br><span class="line">        <span class="keyword">return</span> ServerResponse.ok().body(<span class="keyword">new</span> <span class="title class_">Pig</span>(<span class="string">&quot;zhangsan&quot;</span>, <span class="number">18</span>));</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>







<h2 id="Spring基础配置"><a href="#Spring基础配置" class="headerlink" title="Spring基础配置"></a>Spring基础配置</h2><h5 id="1-Spring启动banner的自定义设置"><a href="#1-Spring启动banner的自定义设置" class="headerlink" title="1.Spring启动banner的自定义设置"></a>1.Spring启动banner的自定义设置</h5><p>rouserces下创建banner.txt</p>
<p>配置:</p>
<figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">spring.banner.location</span> = <span class="string">文件路径</span></span><br></pre></td></tr></table></figure>





<h2 id="Spring整合SSM"><a href="#Spring整合SSM" class="headerlink" title="Spring整合SSM"></a>Spring整合SSM</h2><p>导入ssm依赖</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">mybatis</span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.mybatis.spring.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>mybatis-spring-boot-starter<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>3.0.1<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"></span><br><span class="line">mysql</span><br><span class="line">	<span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>mysql<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>mysql-connector-java<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">version</span>&gt;</span>8.0.33<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"></span><br><span class="line">mybatisPlus</span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.baomidou<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>mybatis-plus-boot-starter<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>3.4.2<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>配置数据源</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">spring.datasource.url=jdbc:mysql:<span class="comment">//192.168.200.100:3306/demo</span></span><br><span class="line">spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver</span><br><span class="line">spring.datasource.username=root</span><br><span class="line">spring.datasource.password=<span class="number">123456</span></span><br><span class="line">spring.datasource.type=com.zaxxer.hikari.HikariDataSource</span><br></pre></td></tr></table></figure>

<p>配置mybatis</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">//指定mapper映射文件位置</span><br><span class="line">mybatis.mapper-locations=classpath:/mapper/*.xml</span><br><span class="line">//参数项调整</span><br><span class="line">mybatis.configuration.map-underscore-to-camel-case=true</span><br></pre></td></tr></table></figure>

<p>CRUD编写</p>
<ul>
<li>编写Bean</li>
<li>编写Mapper</li>
<li>使用<code>mybatisx</code>插件，快速生成MapperXML</li>
<li>测试CRUD</li>
</ul>
<h3 id="解决两者冲突"><a href="#解决两者冲突" class="headerlink" title="解决两者冲突"></a>解决两者冲突</h3><p>原项目系统中已经引入了 Mybatis 和 pagehelper ，当引入Mybatis-plus 后启动项目报错 SqlSessionFactory 错误，排查原因后为依赖冲突导致，需排除部分jar包，并修改相关配置。</p>
<p><strong>mybatis配置类-springboot</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="meta">@MapperScan(&quot;MainApplication.mapper&quot;)</span> <span class="comment">// 指定Mapper接口的包路径</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MyBatisConfig</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="keyword">public</span> SqlSessionFactory <span class="title function_">sqlSessionFactory</span><span class="params">(DataSource dataSource)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        <span class="comment">//为了配合两者共同使用</span></span><br><span class="line">        <span class="type">MybatisSqlSessionFactoryBean</span> <span class="variable">sessionFactoryBean</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">MybatisSqlSessionFactoryBean</span>();</span><br><span class="line">        sessionFactoryBean.setDataSource(dataSource);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 配置其他MyBatis属性</span></span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> sessionFactoryBean.getObject();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="keyword">public</span> SqlSessionTemplate <span class="title function_">sqlSessionTemplate</span><span class="params">(SqlSessionFactory sqlSessionFactory)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">SqlSessionTemplate</span>(sqlSessionFactory);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>1.mybatis中</strong></p>
<!-- Spring-Mybatis -->
<pre><code>    &lt;dependency&gt;
        &lt;groupId&gt;org.mybatis.spring.boot&lt;/groupId&gt;
        &lt;artifactId&gt;mybatis-spring-boot-starter&lt;/artifactId&gt;
        &lt;version&gt;1.3.2&lt;/version&gt;
        &lt;!--原Mybatis中需排除下面2个依赖--&gt;
        &lt;exclusions&gt;
            &lt;exclusion&gt;
                &lt;groupId&gt;org.mybatis&lt;/groupId&gt;
                &lt;artifactId&gt;mybatis&lt;/artifactId&gt;
            &lt;/exclusion&gt;
            &lt;exclusion&gt;
                &lt;groupId&gt;org.mybatis&lt;/groupId&gt;
                &lt;artifactId&gt;mybatis-spring&lt;/artifactId&gt;
            &lt;/exclusion&gt;
        &lt;/exclusions&gt;
    &lt;/dependency&gt;
</code></pre>
<ol start="2">
<li><strong>pagehelper 中</strong></li>
</ol>
<!-- 分页插件 用于分页查询 -->
<pre><code>    &lt;dependency&gt;
        &lt;groupId&gt;com.github.pagehelper&lt;/groupId&gt;
        &lt;artifactId&gt;pagehelper-spring-boot-starter&lt;/artifactId&gt;
        &lt;version&gt;1.2.3&lt;/version&gt;
        &lt;!--需排除下面包--&gt;
        &lt;exclusions&gt;
            &lt;exclusion&gt;
                &lt;groupId&gt;org.mybatis.spring.boot&lt;/groupId&gt;
                &lt;artifactId&gt;mybatis-spring-boot-starter&lt;/artifactId&gt;
            &lt;/exclusion&gt;
        &lt;/exclusions&gt;
    &lt;/dependency&gt;
</code></pre>
<p>3**.引入Mybatis-plus**</p>
<!--引入Mybatis-plus-->
<pre><code>    &lt;dependency&gt;
        &lt;groupId&gt;com.baomidou&lt;/groupId&gt;
        &lt;artifactId&gt;mybatis-plus-boot-starter&lt;/artifactId&gt;
        &lt;version&gt;3.3.2&lt;/version&gt;
    &lt;/dependency&gt;
</code></pre>
<p><strong>4.引入autoconfigure</strong></p>
<!--引入autoconfigure-->
<pre><code>    &lt;dependency&gt;
        &lt;groupId&gt;org.mybatis.spring.boot&lt;/groupId&gt;
        &lt;artifactId&gt;mybatis-spring-boot-autoconfigure&lt;/artifactId&gt;
        &lt;version&gt;2.1.4&lt;/version&gt;
    &lt;/dependency&gt;
</code></pre>
<h3 id="整合其他数据源"><a href="#整合其他数据源" class="headerlink" title="整合其他数据源"></a>整合其他数据源</h3><figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#数据源基本配置</span></span><br><span class="line"><span class="attr">spring.datasource.url</span>=<span class="string">jdbc:mysql://192.168.200.100:3306/demo</span></span><br><span class="line"><span class="attr">spring.datasource.driver-class-name</span>=<span class="string">com.mysql.cj.jdbc.Driver</span></span><br><span class="line"><span class="attr">spring.datasource.username</span>=<span class="string">root</span></span><br><span class="line"><span class="attr">spring.datasource.password</span>=<span class="string">123456</span></span><br><span class="line"><span class="attr">spring.datasource.type</span>=<span class="string">com.alibaba.druid.pool.DruidDataSource</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment"># 配置StatFilter监控</span></span><br><span class="line"><span class="attr">spring.datasource.druid.filter.stat.enabled</span>=<span class="string">true</span></span><br><span class="line"><span class="attr">spring.datasource.druid.filter.stat.db-type</span>=<span class="string">mysql</span></span><br><span class="line"><span class="attr">spring.datasource.druid.filter.stat.log-slow-sql</span>=<span class="string">true</span></span><br><span class="line"><span class="attr">spring.datasource.druid.filter.stat.slow-sql-millis</span>=<span class="string">2000</span></span><br><span class="line"><span class="comment"># 配置WallFilter防火墙</span></span><br><span class="line"><span class="attr">spring.datasource.druid.filter.wall.enabled</span>=<span class="string">true</span></span><br><span class="line"><span class="attr">spring.datasource.druid.filter.wall.db-type</span>=<span class="string">mysql</span></span><br><span class="line"><span class="attr">spring.datasource.druid.filter.wall.config.delete-allow</span>=<span class="string">false</span></span><br><span class="line"><span class="attr">spring.datasource.druid.filter.wall.config.drop-table-allow</span>=<span class="string">false</span></span><br><span class="line"><span class="comment"># 配置监控页，内置监控页面的首页是 /druid/index.html</span></span><br><span class="line"><span class="attr">spring.datasource.druid.stat-view-servlet.enabled</span>=<span class="string">true</span></span><br><span class="line"><span class="attr">spring.datasource.druid.stat-view-servlet.login-username</span>=<span class="string">admin</span></span><br><span class="line"><span class="attr">spring.datasource.druid.stat-view-servlet.login-password</span>=<span class="string">admin</span></span><br><span class="line"><span class="attr">spring.datasource.druid.stat-view-servlet.allow</span>=<span class="string">*</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment"># 其他 Filter 配置不再演示</span></span><br><span class="line"><span class="comment"># 目前为以下 Filter 提供了配置支持，请参考文档或者根据IDE提示（spring.datasource.druid.filter.*）进行配置。</span></span><br><span class="line"><span class="comment"># StatFilter</span></span><br><span class="line"><span class="comment"># WallFilter</span></span><br><span class="line"><span class="comment"># ConfigFilter</span></span><br><span class="line"><span class="comment"># EncodingConvertFilter</span></span><br><span class="line"><span class="comment"># Slf4jLogFilter</span></span><br><span class="line"><span class="comment"># Log4jFilter</span></span><br><span class="line"><span class="comment"># Log4j2Filter</span></span><br><span class="line"><span class="comment"># CommonsLogFilter</span></span><br><span class="line"></span><br></pre></td></tr></table></figure>

<h3 id="使用MybatisX快速创建"><a href="#使用MybatisX快速创建" class="headerlink" title="使用MybatisX快速创建"></a>使用MybatisX快速创建</h3><p>选择mp 3.0版本 生成代码后</p>
<p>编辑mybatisconfig配置类 </p>
<h3 id="分页插件"><a href="#分页插件" class="headerlink" title="分页插件"></a><strong>分页插件</strong></h3><p>用于实现分页查询</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="meta">@MapperScan(&quot;scan.your.mapper.package&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MybatisPlusConfig</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 添加分页插件</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="keyword">public</span> MybatisPlusInterceptor <span class="title function_">mybatisPlusInterceptor</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="type">MybatisPlusInterceptor</span> <span class="variable">interceptor</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">MybatisPlusInterceptor</span>();</span><br><span class="line">        interceptor.addInnerInterceptor(<span class="keyword">new</span> <span class="title class_">PaginationInnerInterceptor</span>(DbType.MYSQL));<span class="comment">//如果配置多个插件,切记分页最后添加</span></span><br><span class="line">        <span class="comment">//interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); 如果有多数据源可以不配具体类型 否则都建议配上具体的DbType</span></span><br><span class="line">        <span class="keyword">return</span> interceptor;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>分页查询的例子</strong>:</p>
<p>以下是使用 MyBatis-Plus 分页插件的基本步骤：</p>
<ol>
<li><p><strong>添加依赖：</strong> 在你的项目中添加 MyBatis-Plus 的依赖。你可以通过 Maven 或 Gradle 来添加依赖。在 Maven 中，添加如下依赖：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.baomidou<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>mybatis-plus-boot-starter<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>最新版本<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>你可以在 <a target="_blank" rel="noopener" href="https://github.com/baomidou/mybatis-plus/releases">MyBatis-Plus GitHub Release</a> 页面找到最新版本。</p>
</li>
<li><p><strong>配置分页插件：</strong> 在 Spring Boot 项目的配置文件中，配置 MyBatis-Plus 的分页插件。在 <code>application.yml</code> 或 <code>application.properties</code> 中添加以下配置：</p>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">mybatis-plus:</span></span><br><span class="line">  <span class="attr">configuration:</span></span><br><span class="line">    <span class="comment"># 开启驼峰命名规则</span></span><br><span class="line">    <span class="attr">map-underscore-to-camel-case:</span> <span class="literal">true</span></span><br><span class="line">    <span class="comment"># 使用自带的分页插件</span></span><br><span class="line">    <span class="attr">pagehelper:</span></span><br><span class="line">      <span class="attr">helperDialect:</span> <span class="string">mysql</span></span><br><span class="line">      <span class="attr">reasonable:</span> <span class="literal">true</span></span><br></pre></td></tr></table></figure>
</li>
<li><p><strong>在 Mapper 中使用分页：</strong> 在 MyBatis 的 Mapper 接口中，可以使用 MyBatis-Plus 提供的 <code>IPage</code> 对象进行分页查询。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> com.baomidou.mybatisplus.core.mapper.BaseMapper;</span><br><span class="line"><span class="keyword">import</span> com.baomidou.mybatisplus.core.metadata.IPage;</span><br><span class="line"><span class="keyword">import</span> com.baomidou.mybatisplus.extension.plugins.pagination.Page;</span><br><span class="line"><span class="keyword">import</span> your.<span class="keyword">package</span>.entity.YourEntity;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">YourEntityMapper</span> <span class="keyword">extends</span> <span class="title class_">BaseMapper</span>&lt;YourEntity&gt; &#123;</span><br><span class="line">    IPage&lt;YourEntity&gt; <span class="title function_">selectPageVo</span><span class="params">(Page&lt;?&gt; page, <span class="meta">@Param(&quot;condition&quot;)</span> YourEntity condition)</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
<li><p><strong>在 Service 层调用分页查询：</strong> 在 Service 层调用 Mapper 中定义的分页查询方法。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> com.baomidou.mybatisplus.core.metadata.IPage;</span><br><span class="line"><span class="keyword">import</span> com.baomidou.mybatisplus.extension.plugins.pagination.Page;</span><br><span class="line"><span class="keyword">import</span> org.springframework.beans.factory.annotation.Autowired;</span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Service;</span><br><span class="line"><span class="keyword">import</span> your.<span class="keyword">package</span>.entity.YourEntity;</span><br><span class="line"><span class="keyword">import</span> your.<span class="keyword">package</span>.mapper.YourEntityMapper;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Service</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">YourEntityService</span> &#123;</span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> YourEntityMapper yourEntityMapper;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> IPage&lt;YourEntity&gt; <span class="title function_">selectPageVo</span><span class="params">(Page&lt;?&gt; page, YourEntity condition)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> yourEntityMapper.selectPageVo(page, condition);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
<li><p><strong>在 Controller 层调用 Service 分页查询：</strong> 在 Controller 层调用 Service 层的分页查询方法。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> com.baomidou.mybatisplus.core.metadata.IPage;</span><br><span class="line"><span class="keyword">import</span> com.baomidou.mybatisplus.extension.plugins.pagination.Page;</span><br><span class="line"><span class="keyword">import</span> org.springframework.beans.factory.annotation.Autowired;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.GetMapping;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.RequestMapping;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.RequestParam;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.RestController;</span><br><span class="line"><span class="keyword">import</span> your.<span class="keyword">package</span>.entity.YourEntity;</span><br><span class="line"><span class="keyword">import</span> your.<span class="keyword">package</span>.service.YourEntityService;</span><br><span class="line"></span><br><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@RequestMapping(&quot;/yourEntity&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">YourEntityController</span> &#123;</span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> YourEntityService yourEntityService;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@GetMapping(&quot;/page&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> IPage&lt;YourEntity&gt; <span class="title function_">selectPageVo</span><span class="params">(<span class="meta">@RequestParam(defaultValue = &quot;1&quot;)</span> <span class="type">long</span> current,</span></span><br><span class="line"><span class="params">                                         <span class="meta">@RequestParam(defaultValue = &quot;10&quot;)</span> <span class="type">long</span> size,</span></span><br><span class="line"><span class="params">                                         YourEntity condition)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> yourEntityService.selectPageVo(<span class="keyword">new</span> <span class="title class_">Page</span>&lt;&gt;(current, size), condition);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li>
</ol>
<p>通过以上步骤，你就可以在 Spring Boot 项目中使用 MyBatis-Plus 分页插件来进行分页查询操作。这样的方式使得分页查询变得简单且易于维护。</p>
<h3 id="逻辑删除"><a href="#逻辑删除" class="headerlink" title="逻辑删除"></a>逻辑删除</h3><p>逻辑删除是指在数据库中并没有真正删除记录，而是通过某种方式标记这些记录为已删除状态，以便在查询时排除这些已删除的记录。这通常用于保留数据的完整性，同时避免真实删除数据可能引发的问题。</p>
<p>MyBatis中，逻辑删除通常通过在数据库表中添加一个表示删除状态的字段来实现，例如添加一个名为<code>is_deleted</code>的字段，用于标识记录是否被删除。这个字段的值可能是一个布尔值（例如<code>true</code>表示已删除，<code>false</code>表示未删除），也可以是一个表示删除状态的标识（例如<code>1</code>表示已删除，<code>0</code>表示未删除）</p>
<p>使用方法</p>
<figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">mybatis-plus</span>:<span class="string"></span></span><br><span class="line">  <span class="attr">global-config</span>:<span class="string"></span></span><br><span class="line">    <span class="attr">db-config</span>:<span class="string"></span></span><br><span class="line">      <span class="attr">logic-delete-field</span>: <span class="string">flag # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)</span></span><br><span class="line">      <span class="attr">logic-delete-value</span>: <span class="string">1 # 逻辑已删除值(默认为 1)</span></span><br><span class="line">      <span class="attr">logic-not-delete-value</span>: <span class="string">0 # 逻辑未删除值(默认为 0)</span></span><br></pre></td></tr></table></figure>

<p>实体类字段上加@TableLogic</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@TableLogic</span></span><br><span class="line"><span class="keyword">private</span> Integer deleted;</span><br></pre></td></tr></table></figure>





<h2 id="Spring整合redis"><a href="#Spring整合redis" class="headerlink" title="Spring整合redis"></a>Spring整合redis</h2><h3 id="默认Redis"><a href="#默认Redis" class="headerlink" title="默认Redis"></a>默认Redis</h3><p>首先导入依赖</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-data-redis<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"></span><br><span class="line">连接池</span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.apache.commons<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>commons-pool2<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>配置</p>
<figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">data</span>:<span class="string"></span></span><br><span class="line">  <span class="attr">redis</span>:<span class="string"></span></span><br><span class="line">    <span class="attr">host</span>: <span class="string">8.219.11.28</span></span><br><span class="line">    <span class="attr">port</span>: <span class="string">6379</span></span><br><span class="line">    <span class="attr">password</span>: <span class="string">zmzm1036</span></span><br><span class="line">    <span class="attr">database</span>: <span class="string">0</span></span><br><span class="line"></span><br><span class="line">    <span class="attr">lettuce</span>:<span class="string"></span></span><br><span class="line">      <span class="attr">pool</span>:<span class="string"></span></span><br><span class="line">        <span class="attr">max-active</span>: <span class="string">10</span></span><br><span class="line">        <span class="attr">max-idle</span>: <span class="string">10</span></span><br><span class="line">        <span class="attr">min-idle</span>: <span class="string">1</span></span><br><span class="line">        <span class="attr">time-between-eviction-runs</span>: <span class="string">10s</span></span><br></pre></td></tr></table></figure>

<p>测试</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Autowired</span></span><br><span class="line">StringRedisTemplate redisTemplate;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Test</span></span><br><span class="line"><span class="keyword">void</span> <span class="title function_">redisTest</span><span class="params">()</span>&#123;</span><br><span class="line">    redisTemplate.opsForValue().set(<span class="string">&quot;a&quot;</span>,<span class="string">&quot;1234&quot;</span>);</span><br><span class="line">    Assertions.assertEquals(<span class="string">&quot;1234&quot;</span>,redisTemplate.opsForValue().get(<span class="string">&quot;a&quot;</span>));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="redis定制化配置"><a href="#redis定制化配置" class="headerlink" title="redis定制化配置"></a>redis定制化配置</h3><p>序列化机制</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">AppRedisConfiguration</span> &#123;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 允许Object类型的key-value，都可以被转为json进行存储。</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> redisConnectionFactory 自动配置好了连接工厂</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="keyword">public</span> RedisTemplate&lt;Object, Object&gt; <span class="title function_">redisTemplate</span><span class="params">(RedisConnectionFactory redisConnectionFactory)</span> &#123;</span><br><span class="line">        RedisTemplate&lt;Object, Object&gt; template = <span class="keyword">new</span> <span class="title class_">RedisTemplate</span>&lt;&gt;();</span><br><span class="line">        template.setConnectionFactory(redisConnectionFactory);</span><br><span class="line">        <span class="comment">//把对象转为json字符串的序列化工具</span></span><br><span class="line">        template.setDefaultSerializer(<span class="keyword">new</span> <span class="title class_">GenericJackson2JsonRedisSerializer</span>());</span><br><span class="line">        <span class="keyword">return</span> template;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>





<h3 id="redis依赖"><a href="#redis依赖" class="headerlink" title="redis依赖"></a>redis依赖</h3><p>RedisTemplate、StringRedisTemplate： 操作redis的工具类 <strong>要从redis的连接工厂获取链接才能操作redis</strong></p>
<p>依赖</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-data-redis<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">exclusions</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">exclusion</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>io.lettuce<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>lettuce-core<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;/<span class="name">exclusion</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="name">exclusions</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">&lt;!--        切换 jedis 作为操作redis的底层客户端--&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>redis.clients<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>jedis<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>配置更改redis的操作底层</p>
<figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#redis的url和端口</span></span><br><span class="line"><span class="attr">spring.data.redis.host</span>=<span class="string">8.130.74.183</span></span><br><span class="line"><span class="attr">spring.data.redis.port</span>=<span class="string">6379</span></span><br><span class="line"><span class="comment">#spring.data.redis.client-type=lettuce</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">#设置lettuce的底层参数</span></span><br><span class="line"><span class="comment">#spring.data.redis.lettuce.pool.enabled=true</span></span><br><span class="line"><span class="comment">#spring.data.redis.lettuce.pool.max-active=8</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">#切换为jedis操作redis</span></span><br><span class="line"><span class="attr">spring.data.redis.client-type</span>=<span class="string">jedis</span></span><br><span class="line"><span class="attr">spring.data.redis.jedis.pool.enabled</span>=<span class="string">true</span></span><br><span class="line"><span class="attr">spring.data.redis.jedis.pool.max-active</span>=<span class="string">8</span></span><br></pre></td></tr></table></figure>



<h3 id="强大工具SpringCache"><a href="#强大工具SpringCache" class="headerlink" title="强大工具SpringCache"></a>强大工具SpringCache</h3><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-data-redis<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"></span><br></pre></td></tr></table></figure>

<figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">spring</span>:<span class="string"></span></span><br><span class="line">    <span class="attr">redis</span>:<span class="string"></span></span><br><span class="line">        <span class="attr">host</span>: <span class="string">118.xx.xx.xxx # Redis服务器地址</span></span><br><span class="line">        <span class="attr">database</span>: <span class="string">0 # Redis数据库索引（默认为0）</span></span><br><span class="line">        <span class="attr">port</span>: <span class="string">6379 # Redis服务器连接端口</span></span><br><span class="line">        <span class="attr">password</span>: <span class="string">xx # Redis服务器连接密码（默认为空）</span></span><br><span class="line">        <span class="attr">timeout</span>: <span class="string">1000ms # 连接超时时间（毫秒）</span></span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>新增 RedisConfig.java 类，通过 RedisTemplate 设置 JSON 格式的序列化器，这样的话存储到 Redis 里的数据将是有类型的 JSON 数据</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@EnableCaching</span></span><br><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">RedisConfig</span> <span class="keyword">extends</span> <span class="title class_">CachingConfigurerSupport</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="keyword">public</span> RedisTemplate&lt;String, Object&gt; <span class="title function_">redisTemplate</span><span class="params">(RedisConnectionFactory redisConnectionFactory)</span> &#123;</span><br><span class="line">        RedisTemplate&lt;String, Object&gt; redisTemplate = <span class="keyword">new</span> <span class="title class_">RedisTemplate</span>&lt;&gt;();</span><br><span class="line">        redisTemplate.setConnectionFactory(redisConnectionFactory);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 通过 Jackson 组件进行序列化</span></span><br><span class="line">        RedisSerializer&lt;Object&gt; serializer = redisSerializer();</span><br><span class="line"></span><br><span class="line">        <span class="comment">// key 和 value</span></span><br><span class="line">        <span class="comment">// 一般来说， redis-key采用字符串序列化；</span></span><br><span class="line">        <span class="comment">// redis-value采用json序列化， json的体积小，可读性高，不需要实现serializer接口。</span></span><br><span class="line">        redisTemplate.setKeySerializer(<span class="keyword">new</span> <span class="title class_">StringRedisSerializer</span>());</span><br><span class="line">        redisTemplate.setValueSerializer(serializer);</span><br><span class="line"></span><br><span class="line">        redisTemplate.setHashKeySerializer(<span class="keyword">new</span> <span class="title class_">StringRedisSerializer</span>());</span><br><span class="line">        redisTemplate.setHashValueSerializer(serializer);</span><br><span class="line"></span><br><span class="line">        redisTemplate.afterPropertiesSet();</span><br><span class="line">        <span class="keyword">return</span> redisTemplate;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="keyword">public</span> RedisSerializer&lt;Object&gt; <span class="title function_">redisSerializer</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="comment">//创建JSON序列化器</span></span><br><span class="line">        Jackson2JsonRedisSerializer&lt;Object&gt; serializer = <span class="keyword">new</span> <span class="title class_">Jackson2JsonRedisSerializer</span>&lt;&gt;(Object.class);</span><br><span class="line">        <span class="type">ObjectMapper</span> <span class="variable">objectMapper</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectMapper</span>();</span><br><span class="line">        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);</span><br><span class="line">        <span class="comment">// https://www.cnblogs.com/shanheyongmu/p/15157378.html</span></span><br><span class="line">        <span class="comment">// objectMapper.enableDefaultTyping()被弃用</span></span><br><span class="line">        objectMapper.activateDefaultTyping(</span><br><span class="line">                LaissezFaireSubTypeValidator.instance,</span><br><span class="line">                ObjectMapper.DefaultTyping.NON_FINAL,</span><br><span class="line">                JsonTypeInfo.As.WRAPPER_ARRAY);</span><br><span class="line">        serializer.setObjectMapper(objectMapper);</span><br><span class="line">        <span class="keyword">return</span> serializer;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Bean</span></span><br><span class="line"><span class="keyword">public</span> RedisCacheManager <span class="title function_">redisCacheManager</span><span class="params">(RedisConnectionFactory redisConnectionFactory)</span> &#123;</span><br><span class="line">    <span class="type">RedisCacheWriter</span> <span class="variable">redisCacheWriter</span> <span class="operator">=</span> RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory);</span><br><span class="line">    <span class="comment">//设置Redis缓存有效期为1天</span></span><br><span class="line">    <span class="type">RedisCacheConfiguration</span> <span class="variable">redisCacheConfiguration</span> <span class="operator">=</span> RedisCacheConfiguration.defaultCacheConfig()</span><br><span class="line">            .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer())).entryTtl(Duration.ofDays(<span class="number">1</span>));</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">RedisCacheManager</span>(redisCacheWriter, redisCacheConfiguration);</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>







<h2 id="Spring外部化配置"><a href="#Spring外部化配置" class="headerlink" title="Spring外部化配置"></a>Spring外部化配置</h2><h3 id="配置优先级"><a href="#配置优先级" class="headerlink" title="配置优先级"></a>配置优先级</h3><p>Spring Boot 允许将<strong>配置外部化</strong>，以便可以在不同的环境中使用相同的应用程序代码。</p>
<p>我们可以使用各种<strong>外部配置源</strong>，包括Java Properties文件、YAML文件、环境变量和命令行参数。</p>
<p><strong>@Value</strong>可以获取值，也可以用**@ConfigurationProperties**将所有属性绑定到java object中</p>
<h4 id="使用application-properties或application-yml文件："><a href="#使用application-properties或application-yml文件：" class="headerlink" title="使用application.properties或application.yml文件："></a>使用<code>application.properties</code>或<code>application.yml</code>文件：</h4><ul>
<li><p>在Spring Boot项目中，可以直接在<code>src/main/resources</code>目录下创建<code>application.properties</code>或<code>application.yml</code>文件，并在其中配置应用程序的属性。</p>
</li>
<li><p>例如，在<code>application.properties</code>文件中配置一个属性：</p>
<figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">myapp.name</span>=<span class="string">My Application</span></span><br></pre></td></tr></table></figure>

<p>在代码中使用该属性： Spring会自动加载<code>application.properties</code>或<code>application.yml</code>文件，并将其中的属性值注入到对应的变量中</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Value(&quot;$&#123;myapp.name&#125;&quot;)</span></span><br><span class="line"><span class="keyword">private</span> String appName;</span><br></pre></td></tr></table></figure></li>
</ul>
<h4 id="使用外部配置文件"><a href="#使用外部配置文件" class="headerlink" title="使用外部配置文件"></a>使用外部配置文件</h4><ul>
<li><p>可以将配置信息放在一个独立的外部文件中，然后通过Spring的<code>@PropertySource</code>注解来加载该文件。</p>
</li>
<li><p>例如，创建一个名为<code>app.properties</code>的外部文件，并在其中配置一个属性：</p>
<figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">myapp.name</span>=<span class="string">My Application	</span></span><br></pre></td></tr></table></figure>

<p>在代码中使用该属性：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Value(&quot;$&#123;myapp.name&#125;&quot;)</span></span><br><span class="line"><span class="keyword">private</span> String appName;</span><br></pre></td></tr></table></figure>

<p>在Spring的配置类上添加<code>@PropertySource</code>注解，并指定要加载的外部配置文件：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="meta">@PropertySource(&quot;classpath:app.properties&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">AppConfig</span> &#123;</span><br><span class="line">    <span class="comment">// ...</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<ul>
<li>这样，Spring会加载<code>app.properties</code>文件，并将其中的属性值注入到对应的变量中。</li>
</ul>
</li>
</ul>
<h2 id="Spring-–-Junit-单元测试"><a href="#Spring-–-Junit-单元测试" class="headerlink" title="Spring  – Junit 单元测试"></a>Spring  – Junit 单元测试</h2><h3 id="DisplayName-指定测试单元的名字"><a href="#DisplayName-指定测试单元的名字" class="headerlink" title="@DisplayName 指定测试单元的名字"></a>@DisplayName 指定测试单元的名字</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@SpringBootTest</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MainApplicationTest</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//这里可以注入ioc容器中任意的组件来进行测试功能</span></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    pigBisHandler pigBisHandler;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Test</span></span><br><span class="line">    <span class="meta">@DisplayName(&quot;测试TestPigBisHandler&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">TestPigBisHandler</span><span class="params">()</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        System.out.println(pigBisHandler.handlePig(<span class="literal">null</span>));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="BeforeEach-BeforeAll-AfterAll-AfterEach"><a href="#BeforeEach-BeforeAll-AfterAll-AfterEach" class="headerlink" title="@BeforeEach @BeforeAll @AfterAll @AfterEach"></a>@BeforeEach @BeforeAll @AfterAll @AfterEach</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@BeforeAll</span></span><br><span class="line">   <span class="meta">@Test</span></span><br><span class="line">   <span class="comment">//必须指定为静态方法</span></span><br><span class="line">   <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">init</span><span class="params">()</span> &#123;</span><br><span class="line">       System.out.println(<span class="string">&quot;所有方法运行前 运行一次&quot;</span>);</span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line">   <span class="meta">@BeforeEach</span></span><br><span class="line">   <span class="meta">@Test</span></span><br><span class="line">   <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">init2</span><span class="params">()</span> &#123;</span><br><span class="line">       System.out.println(<span class="string">&quot;每个方法运行后 都要运行一次&quot;</span>);</span><br><span class="line">   </span><br><span class="line">   </span><br></pre></td></tr></table></figure>

<h3 id="Test提供的断言工具Assertions"><a href="#Test提供的断言工具Assertions" class="headerlink" title="Test提供的断言工具Assertions"></a>Test提供的断言工具Assertions</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">https://junit.org/junit5/docs/current/user-guide/  junitAPI</span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Test</span></span><br><span class="line">   <span class="meta">@DisplayName(&quot;测试断言信息&quot;)</span></span><br><span class="line">   <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">TestAssertUtils</span><span class="params">()</span> &#123;</span><br><span class="line">       <span class="type">int</span> <span class="variable">a</span> <span class="operator">=</span> <span class="number">2</span>;</span><br><span class="line">       <span class="type">int</span> <span class="variable">b</span> <span class="operator">=</span> <span class="number">1</span>;</span><br><span class="line">       <span class="comment">//断言a+b是否是3 如果是 那么就正常运行 不是 就报错</span></span><br><span class="line">       Assertions.assertEquals(<span class="number">3</span>,a+b);</span><br><span class="line">       System.out.println(<span class="string">&quot;执行成功!!&quot;</span>);</span><br><span class="line">   &#125;</span><br></pre></td></tr></table></figure>

<p><strong>断言报错</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">org.opentest4j.AssertionFailedError: </span><br><span class="line">预期:<span class="number">1</span></span><br><span class="line">实际:<span class="number">3</span></span><br><span class="line">&lt;点击以查看差异&gt;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">	at org.junit.jupiter.api.AssertionFailureBuilder.build(AssertionFailureBuilder.java:<span class="number">151</span>) ......</span><br><span class="line"></span><br><span class="line">进程已结束,退出代码-<span class="number">1</span></span><br><span class="line"></span><br></pre></td></tr></table></figure>

<h3 id="参数化测试"><a href="#参数化测试" class="headerlink" title="参数化测试"></a>参数化测试</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//指定参数</span></span><br><span class="line"><span class="comment">//  @Test</span></span><br><span class="line">    <span class="meta">@ParameterizedTest</span></span><br><span class="line">    <span class="meta">@ValueSource(strings = &#123;&quot;one&quot;, &quot;two&quot;, &quot;three&quot;&#125;)</span></span><br><span class="line">    <span class="meta">@DisplayName(&quot;参数化测试&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">TestAssertUtils</span><span class="params">(String string)</span> &#123;</span><br><span class="line">        Assertions.assertNotNull(StringUtils.isNotBlank(string));</span><br><span class="line">        System.out.println(<span class="string">&quot;执行成功!!&quot;</span>);</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//通过方法来找参数</span></span><br><span class="line"><span class="meta">@ParameterizedTest</span></span><br><span class="line">    <span class="meta">@MethodSource(&quot;getStrings&quot;)</span></span><br><span class="line">    <span class="meta">@DisplayName(&quot;参数化测试&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">TestStreamMethod</span><span class="params">(String value)</span> &#123;</span><br><span class="line">        Assertions.assertTrue(StringUtils.isNotBlank(value));</span><br><span class="line">        System.out.println(<span class="string">&quot;执行成功!!&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> Stream&lt;String&gt; <span class="title function_">getStrings</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> Stream.of(<span class="string">&quot;1&quot;</span>, <span class="string">&quot;2&quot;</span>);</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>





<h1 id="SpringBoot-核心"><a href="#SpringBoot-核心" class="headerlink" title="SpringBoot 核心"></a>SpringBoot 核心</h1><p><strong>生命周期监听</strong></p>
<p>METAINFO里创建springfactories文件</p>
<figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">org.springframework.boot.SpringApplicationRunListener</span>=<span class="string">MainApplication.listener.MyAppListener</span></span><br></pre></td></tr></table></figure>

<p><strong>创建监听器类</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> MainApplication.listener;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.ConfigurableBootstrapContext;</span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.SpringApplicationRunListener;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.ConfigurableApplicationContext;</span><br><span class="line"><span class="keyword">import</span> org.springframework.core.env.ConfigurableEnvironment;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.time.Duration;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MyAppListener</span> <span class="keyword">implements</span> <span class="title class_">SpringApplicationRunListener</span> &#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">starting</span><span class="params">(ConfigurableBootstrapContext bootstrapContext)</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;===正在启动===&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">environmentPrepared</span><span class="params">(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment)</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;环境准备完成&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">	</span><br><span class="line">    <span class="comment">//ioc容器已经准备好 主配置类还没加载</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">contextPrepared</span><span class="params">(ConfigurableApplicationContext context)</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;上下文准备完成&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">contextLoaded</span><span class="params">(ConfigurableApplicationContext context)</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;Ioc加载完成&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">started</span><span class="params">(ConfigurableApplicationContext context, Duration timeTaken)</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;Started启动完成&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">ready</span><span class="params">(ConfigurableApplicationContext context, Duration timeTaken)</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;Ready启动&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">failed</span><span class="params">(ConfigurableApplicationContext context, Throwable exception)</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;启动失败&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">MyAppListener</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="built_in">super</span>();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">hashCode</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">super</span>.hashCode();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">equals</span><span class="params">(Object obj)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">super</span>.equals(obj);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">protected</span> Object <span class="title function_">clone</span><span class="params">()</span> <span class="keyword">throws</span> CloneNotSupportedException &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">super</span>.clone();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">toString</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">super</span>.toString();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">finalize</span><span class="params">()</span> <span class="keyword">throws</span> Throwable &#123;</span><br><span class="line">        <span class="built_in">super</span>.finalize();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p><strong>感知事件的监听器类</strong></p>
<figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">org.springframework.context.ApplicationListener</span>=<span class="string">MainApplication.listener.MyListener</span></span><br></pre></td></tr></table></figure>

<p><strong>这里默认监听的是applicationEvent</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//感知事件变化</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MyListener</span> <span class="keyword">implements</span> <span class="title class_">ApplicationListener</span>&lt;ApplicationEvent&gt; &#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">onApplicationEvent</span><span class="params">(ApplicationEvent event)</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;事件到达&quot;</span> + event);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>





<h2 id="上下文"><a href="#上下文" class="headerlink" title="上下文"></a>上下文</h2><p>Spring 上下文（Spring Context）是 Spring 框架中的一个核心概念，它是一个用于管理和组织应用程序组件的容器。Spring 上下文提供了一种在应用程序中获取 bean 对象、解析依赖关系、进行资源加载和执行其他与应用程序生命周期相关的任务的机制。在 Spring 中，有两种主要的上下文实现：ApplicationContext 和 WebApplicationContext。</p>
<ol>
<li>ApplicationContext:<ul>
<li>ApplicationContext 是 Spring 框架的核心接口，用于表示 Spring 容器。</li>
<li>它是一个以 bean 为中心的容器，负责加载、配置和管理 bean 对象。</li>
<li>提供了许多功能，如事件传播、AOP 支持、国际化、消息资源处理等。</li>
<li>可以通过多种方式进行配置，包括 XML 配置、Java 注解配置和 Java 代码配置。</li>
</ul>
</li>
</ol>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 通过ClassPathXmlApplicationContext加载XML配置文件</span></span><br><span class="line"><span class="type">ApplicationContext</span> <span class="variable">context</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ClassPathXmlApplicationContext</span>(<span class="string">&quot;applicationContext.xml&quot;</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 通过AnnotationConfigApplicationContext加载基于Java注解的配置类</span></span><br><span class="line"><span class="type">ApplicationContext</span> <span class="variable">context</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">AnnotationConfigApplicationContext</span>(AppConfig.class);</span><br></pre></td></tr></table></figure>

<ol>
<li>WebApplicationContext:<ul>
<li>WebApplicationContext 是 ApplicationContext 的一个扩展，专门用于在 Web 应用程序中使用。</li>
<li>它包含了与 Web 应用相关的特定功能，如处理 Web 事件、解析 Web 资源、实现国际化等。</li>
<li>在 Spring MVC 中，WebApplicationContext 负责加载和管理控制器、服务类以及其他与 Web 层相关的组件。</li>
</ul>
</li>
</ol>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 在Spring MVC中，通过XmlWebApplicationContext加载XML配置文件</span></span><br><span class="line"><span class="type">WebApplicationContext</span> <span class="variable">context</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">XmlWebApplicationContext</span>();</span><br><span class="line">((XmlWebApplicationContext) context).setConfigLocation(<span class="string">&quot;/WEB-INF/applicationContext.xml&quot;</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 或者通过AnnotationConfigWebApplicationContext加载基于Java注解的配置类</span></span><br><span class="line"><span class="type">WebApplicationContext</span> <span class="variable">context</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">AnnotationConfigWebApplicationContext</span>();</span><br><span class="line">((AnnotationConfigWebApplicationContext) context).register(AppConfig.class);</span><br></pre></td></tr></table></figure>

<p>Spring 上下文的存在使得开发人员能够更加方便地管理组件之间的依赖关系，并能够通过配置来实现松耦合的设计</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">AppConfig</span> &#123;</span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="keyword">public</span> UserService <span class="title function_">userService</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">UserServiceImpl</span>();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="keyword">public</span> UserRepository <span class="title function_">userRepository</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">JpaUserRepository</span>();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MainApplication</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="type">AnnotationConfigApplicationContext</span> <span class="variable">context</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">AnnotationConfigApplicationContext</span>(AppConfig.class);</span><br><span class="line"></span><br><span class="line">        <span class="type">UserService</span> <span class="variable">userService</span> <span class="operator">=</span> context.getBean(UserService.class);</span><br><span class="line">        <span class="comment">// 使用userService进行业务逻辑处理</span></span><br><span class="line"></span><br><span class="line">        context.close(); <span class="comment">// 关闭应用程序上下文</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line">在这个例子中，AppConfig是一个使用Java配置的Spring配置类，它定义了UserService和UserRepository的Bean。在MainApplication中，我们创建了一个AnnotationConfigApplicationContext作为Spring应用程序上下文，然后从上下文中获取UserService的实例，并使用它进行业务逻辑处理。最后，我们关闭应用程序上下文以释放资源</span><br><span class="line"></span><br></pre></td></tr></table></figure>





<h2 id="九大事件和探针"><a href="#九大事件和探针" class="headerlink" title="九大事件和探针"></a>九大事件和探针</h2><p>ContextRefreshedEvent：当应用上下文被初始化或刷新时触发，这通常发生在应用程序启动时。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ContextRefreshedListener</span> <span class="keyword">implements</span> <span class="title class_">ApplicationListener</span>&lt;ContextRefreshedEvent&gt; &#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">onApplicationEvent</span><span class="params">(ContextRefreshedEvent event)</span> &#123;</span><br><span class="line">        <span class="comment">// 当应用上下文被初始化或刷新时触发的逻辑</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>ContextStartedEvent：当应用上下文启动时触发。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> org.springframework.context.ApplicationListener;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.event.ContextStartedEvent;</span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Component;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ContextStartedListener</span> <span class="keyword">implements</span> <span class="title class_">ApplicationListener</span>&lt;ContextStartedEvent&gt; &#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">onApplicationEvent</span><span class="params">(ContextStartedEvent event)</span> &#123;</span><br><span class="line">        <span class="comment">// 当应用上下文启动时触发的逻辑</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>ContextStoppedEvent：当应用上下文停止时触发。<br>ContextClosedEvent：当应用上下文关闭时触发。<br>RequestHandledEvent：在Web应用程序中，每次HTTP请求被处理完毕时触发。<br>ServletRequestHandledEvent：在基于Servlet的Web应用程序中，每次HTTP请求被处理完毕时触发。<br>SessionStartedEvent：当HTTP会话启动时触发。<br>SessionEndedEvent：当HTTP会话结束时触发。<br>TransactionalEvent：与事务相关的事件，如提交、回滚等</p>
<h2 id="事件监听机制"><a href="#事件监听机制" class="headerlink" title="事件监听机制"></a>事件监听机制</h2><h4 id="用于监听某个事件-做某事情-可以用来加需求的时候用"><a href="#用于监听某个事件-做某事情-可以用来加需求的时候用" class="headerlink" title="用于监听某个事件 做某事情 可以用来加需求的时候用"></a>用于监听某个事件 做某事情 可以用来加需求的时候用</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 定义自定义事件</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MyCustomEvent</span> <span class="keyword">extends</span> <span class="title class_">ApplicationEvent</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">MyCustomEvent</span><span class="params">(Object source)</span> &#123;</span><br><span class="line">        <span class="built_in">super</span>(source);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 可以添加自定义属性和方法</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 发布事件的地方</span></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MyEventPublisher</span> &#123;</span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> ApplicationEventPublisher publisher;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">doSomethingAndPublishEvent</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="comment">// 执行某些操作后发布自定义事件</span></span><br><span class="line">        publisher.publishEvent(<span class="keyword">new</span> <span class="title class_">MyCustomEvent</span>(<span class="built_in">this</span>));</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 监听事件并做出响应</span></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MyEventListener</span> &#123;</span><br><span class="line">    <span class="meta">@EventListener</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">handleCustomEvent</span><span class="params">(MyCustomEvent event)</span> &#123;</span><br><span class="line">        <span class="comment">// 在这里处理自定义事件</span></span><br><span class="line">        <span class="comment">// 例如：执行特定的逻辑</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<h3 id="具体例子-以用户注册后发送欢迎邮件为例"><a href="#具体例子-以用户注册后发送欢迎邮件为例" class="headerlink" title="具体例子 以用户注册后发送欢迎邮件为例"></a>具体例子 以用户注册后发送欢迎邮件为例</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 先写用户注册事件</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">UserRegisteredEvent</span> <span class="keyword">extends</span> <span class="title class_">ApplicationEvent</span> &#123;</span><br><span class="line">    <span class="comment">//谁登陆了 把用户信息传进来</span></span><br><span class="line">    <span class="keyword">private</span> User user;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">UserRegisteredEvent</span><span class="params">(Object source, User user)</span> &#123;</span><br><span class="line">        <span class="built_in">super</span>(source);</span><br><span class="line">        <span class="built_in">this</span>.user = user;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> User <span class="title function_">getUser</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> user;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 用户注册服务</span></span><br><span class="line"><span class="meta">@Service</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">UserRegistrationService</span> &#123;</span><br><span class="line">    <span class="comment">//注入发送事件的对象</span></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> ApplicationEventPublisher eventPublisher;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">registerUser</span><span class="params">(User user)</span> &#123;</span><br><span class="line">        <span class="comment">// 执行用户注册逻辑</span></span><br><span class="line">        <span class="comment">// ...</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">// 创建注册事件的对象 发布用户注册事件</span></span><br><span class="line">        eventPublisher.publishEvent(<span class="keyword">new</span> <span class="title class_">UserRegisteredEvent</span>(<span class="built_in">this</span>, user));</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 监听用户注册事件并发送欢迎邮件或者其他行为</span></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">WelcomeEmailSender</span> &#123;</span><br><span class="line">    <span class="meta">@EventListener</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">sendWelcomeEmail</span><span class="params">(UserRegisteredEvent event)</span> &#123;</span><br><span class="line">        <span class="type">User</span> <span class="variable">user</span> <span class="operator">=</span> event.getUser();</span><br><span class="line">        <span class="comment">// 发送欢迎邮件给新注册用户</span></span><br><span class="line">        <span class="comment">// ...</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<h3 id="再来一个例子-现在已经写好了记录信息和发送邮件的业务，但是还要加一个当用户登陆时，监听事件然后给登录用户发送优惠券的业务"><a href="#再来一个例子-现在已经写好了记录信息和发送邮件的业务，但是还要加一个当用户登陆时，监听事件然后给登录用户发送优惠券的业务" class="headerlink" title="再来一个例子:现在已经写好了记录信息和发送邮件的业务，但是还要加一个当用户登陆时，监听事件然后给登录用户发送优惠券的业务"></a>再来一个例子:现在已经写好了记录信息和发送邮件的业务，但是还要加一个当用户登陆时，监听事件然后给登录用户发送优惠券的业务</h3><h3 id="controller-service"><a href="#controller-service" class="headerlink" title="controller service:"></a>controller service:</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">LoginController</span> &#123;</span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    LoginService loginService;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//注入事件发送器</span></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    LoginEventPublisher publisher;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@GetMapping(&quot;/login&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">Login</span><span class="params">(<span class="meta">@RequestParam(&quot;username&quot;)</span> String username</span></span><br><span class="line"><span class="params">            , <span class="meta">@RequestParam(&quot;userpwd&quot;)</span> String userpwd)</span> &#123;</span><br><span class="line"></span><br><span class="line">        log.info(<span class="string">&quot;用户登录成功&quot;</span>);</span><br><span class="line">		<span class="comment">//已经实现的业务</span></span><br><span class="line">        loginService.getInfo(username);</span><br><span class="line">        loginService.sendMessage(username);</span><br><span class="line">        </span><br><span class="line">        </span><br><span class="line">        <span class="comment">//封装实体对象</span></span><br><span class="line">        <span class="type">EntityUser</span> <span class="variable">user</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">EntityUser</span>(username, userpwd);</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<h3 id="首先编写事件-也就是登录事件需要继承spring的event类"><a href="#首先编写事件-也就是登录事件需要继承spring的event类" class="headerlink" title="首先编写事件 也就是登录事件需要继承spring的event类"></a>首先编写事件 也就是登录事件需要继承spring的event类</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="comment">//登录事件类</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">LoginEvent</span> <span class="keyword">extends</span> <span class="title class_">ApplicationEvent</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> EntityUser user;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//source是传进来的任何东西 在这里是用户对象</span></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">LoginEvent</span><span class="params">(Object source)</span> &#123;</span><br><span class="line">        <span class="built_in">super</span>(source);</span><br><span class="line">        <span class="built_in">this</span>.user = (EntityUser) source;</span><br><span class="line">    &#125;</span><br><span class="line">	</span><br><span class="line">    <span class="comment">//这里一般要写一个方法来记录用户的信息 方便后面的调用</span></span><br><span class="line">    <span class="keyword">public</span> EntityUser <span class="title function_">getUser</span><span class="params">()</span> &#123;</span><br><span class="line">        log.info(<span class="string">&quot;用户信息为&#123;&#125;&quot;</span>, user.toString());</span><br><span class="line">        <span class="keyword">return</span> user;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="然后写一个继承了spring发布事件类的自定义事件发布类-方便监听器监听"><a href="#然后写一个继承了spring发布事件类的自定义事件发布类-方便监听器监听" class="headerlink" title="然后写一个继承了spring发布事件类的自定义事件发布类 方便监听器监听"></a>然后写一个继承了spring发布事件类的自定义事件发布类 方便监听器监听</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="comment">//事件发送器 要调用底层去发事件</span></span><br><span class="line"><span class="meta">@Service</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">LoginEventPublisher</span> <span class="keyword">implements</span> <span class="title class_">ApplicationEventPublisherAware</span> &#123;</span><br><span class="line">    <span class="comment">//自己封装一个 类型为spring默认的事件发布类</span></span><br><span class="line">    ApplicationEventPublisher LoginEventPublisher;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//发送事件的方法</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">sendEvent</span><span class="params">(ApplicationEvent event)</span> &#123;</span><br><span class="line">        <span class="comment">//真正发送事件</span></span><br><span class="line">        LoginEventPublisher.publishEvent(event);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//自动注入了底层发送事件的对象 该方法自动调用</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setApplicationEventPublisher</span><span class="params">(ApplicationEventPublisher applicationEventPublisher)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.LoginEventPublisher = applicationEventPublisher;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<h3 id="写一个监听事件的类LoginEventListener-加了-EventListener后-在容器中可以自动监听事件"><a href="#写一个监听事件的类LoginEventListener-加了-EventListener后-在容器中可以自动监听事件" class="headerlink" title="写一个监听事件的类LoginEventListener 加了@EventListener后 在容器中可以自动监听事件"></a>写一个监听事件的类LoginEventListener 加了@EventListener后 在容器中可以自动监听事件</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">LoginEventListener</span> &#123;</span><br><span class="line">    <span class="comment">//发送优惠券的方法</span></span><br><span class="line">    <span class="meta">@EventListener</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">sendCoupon</span><span class="params">(LoginEvent event)</span> &#123;</span><br><span class="line">        <span class="comment">//获取到用户信息 因为上面的Event类编写了获取用户信息的方法</span></span><br><span class="line">        <span class="type">EntityUser</span> <span class="variable">user</span> <span class="operator">=</span> event.getUser();</span><br><span class="line">        log.info(<span class="string">&quot;事件为&#123;&#125;,并且发送给&#123;&#125;用户了优惠券&quot;</span>, event, user.getUsername());</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="然后在controller中-创建事件对象-注入事件发布对象"><a href="#然后在controller中-创建事件对象-注入事件发布对象" class="headerlink" title="然后在controller中 创建事件对象 注入事件发布对象"></a>然后在controller中 创建事件对象 注入事件发布对象</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//注入事件发送器</span></span><br><span class="line"> 		<span class="meta">@Autowired</span></span><br><span class="line">  	LoginEventPublisher publisher;		</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//创建登录事件</span></span><br><span class="line">      <span class="type">LoginEvent</span> <span class="variable">event</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">LoginEvent</span>(user);</span><br><span class="line"></span><br><span class="line">      <span class="comment">//发送登录事件让别人监听到</span></span><br><span class="line">      publisher.sendEvent(event);</span><br></pre></td></tr></table></figure>



<h2 id="探针机制"><a href="#探针机制" class="headerlink" title="探针机制"></a>探针机制</h2><p>依赖</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-actuator<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>配置探针断点</p>
<figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">management</span>:<span class="string"></span></span><br><span class="line">  <span class="attr">endpoints</span>:<span class="string"></span></span><br><span class="line">    <span class="attr">web</span>:<span class="string"></span></span><br><span class="line">      <span class="attr">exposure</span>:<span class="string"></span></span><br><span class="line">        <span class="attr">include</span>: <span class="string">&quot;*&quot;  # 开启所有端点，也可以指定具体的端点</span></span><br></pre></td></tr></table></figure>

<p>访问</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">访问端点： 启动你的Spring Boot应用程序，然后通过HTTP请求访问探针端点。默认的端点路径为/actuator。</span><br><span class="line"></span><br><span class="line">例如，健康检查端点：http:<span class="comment">//localhost:8080/actuator/health</span></span><br><span class="line">环境信息端点：http:<span class="comment">//localhost:8080/actuator/env</span></span><br><span class="line">其他端点可以参考Spring Boot文档</span><br></pre></td></tr></table></figure>

<p>SpringSecurity强化</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">management:</span><br><span class="line">  endpoints:</span><br><span class="line">    web:</span><br><span class="line">      exposure:</span><br><span class="line">        include: <span class="string">&quot;health,info&quot;</span></span><br><span class="line">  endpoint:</span><br><span class="line">    health:</span><br><span class="line">      show-details: always</span><br></pre></td></tr></table></figure>



<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line">假设你有一个基于Spring Boot的电子商务网站，你可以使用Spring Boot Actuator的<span class="string">&quot;health&quot;</span>和<span class="string">&quot;info&quot;</span>端点来监控和提供应用程序的健康和信息。</span><br><span class="line"></span><br><span class="line">首先，确保在`pom.xml`中包含了Spring Boot Actuator的依赖：</span><br><span class="line"></span><br><span class="line">```xml</span><br><span class="line">&lt;dependency&gt;</span><br><span class="line">    &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;</span><br><span class="line">    &lt;artifactId&gt;spring-boot-starter-actuator&lt;/artifactId&gt;</span><br><span class="line">&lt;/dependency&gt;</span><br><span class="line">```</span><br><span class="line"></span><br><span class="line">然后，你可以配置`management.endpoint.health.show-details`属性来显示更详细的健康信息。接着，可以创建一个自定义的健康指示器来提供应用程序特定的健康信息：</span><br><span class="line"></span><br><span class="line">```java</span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">CustomHealthIndicator</span> <span class="keyword">implements</span> <span class="title class_">HealthIndicator</span> &#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> Health <span class="title function_">health</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="comment">// 在这里编写自定义的健康检查逻辑</span></span><br><span class="line">        <span class="comment">// 例如：检查数据库连接、第三方服务状态等</span></span><br><span class="line">        <span class="comment">// 返回相应的健康状态</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line">```</span><br><span class="line"></span><br><span class="line">对于<span class="string">&quot;info&quot;</span>端点，你可以创建一个自定义的信息端点来提供应用程序特定的信息：</span><br><span class="line"></span><br><span class="line">```java</span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">CustomInfoContributor</span> <span class="keyword">implements</span> <span class="title class_">InfoContributor</span> &#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">contribute</span><span class="params">(Info.Builder builder)</span> &#123;</span><br><span class="line">        <span class="comment">// 在这里添加自定义的应用程序信息</span></span><br><span class="line">        builder.withDetail(<span class="string">&quot;appVersion&quot;</span>, <span class="string">&quot;1.0.0&quot;</span>)</span><br><span class="line">               .withDetail(<span class="string">&quot;author&quot;</span>, <span class="string">&quot;Your Name&quot;</span>)</span><br><span class="line">               .build();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line">```</span><br><span class="line"></span><br><span class="line">最后，你可以通过访问`/actuator/health`和`/actuator/info`端点来查看应用程序的健康状态和自定义信息。这些端点可以帮助你监控应用程序的运行情况并提供自定义信息供其他系统使用。</span><br></pre></td></tr></table></figure>





<h2 id="自定义Swagger"><a href="#自定义Swagger" class="headerlink" title="自定义Swagger"></a>自定义Swagger</h2><p>导入依赖</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springdoc<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>springdoc-openapi-starter-webmvc-ui<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>2.1.0<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>



<p>然后启动服务 访问&#x2F;swagger-ui&#x2F;index.hml</p>
<h4 id="配置"><a href="#配置" class="headerlink" title="配置"></a>配置</h4><figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># /api-docs endpoint custom path 默认 /v3/api-docs</span></span><br><span class="line"><span class="attr">springdoc.api-docs.path</span>=<span class="string">/api-docs</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment"># swagger 相关配置在  springdoc.swagger-ui</span></span><br><span class="line"><span class="comment"># swagger-ui custom path</span></span><br><span class="line"><span class="attr">springdoc.swagger-ui.path</span>=<span class="string">/swagger-ui.html</span></span><br><span class="line"></span><br><span class="line"><span class="attr">springdoc.show-actuator</span>=<span class="string">true</span></span><br></pre></td></tr></table></figure>





<h3 id="Tag描述接口文档的类"><a href="#Tag描述接口文档的类" class="headerlink" title="@Tag描述接口文档的类"></a>@Tag描述接口文档的类</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Tag(name = &quot;登录&quot; ,description = &quot;登录接口&quot;)</span></span><br><span class="line">   <span class="meta">@GetMapping(&quot;/login&quot;)</span></span><br><span class="line">   <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">Login</span><span class="params">(<span class="meta">@RequestParam(&quot;username&quot;)</span> String username</span></span><br><span class="line"><span class="params">           , <span class="meta">@RequestParam(&quot;userpwd&quot;)</span> String userpwd)</span> &#123;</span><br><span class="line"></span><br></pre></td></tr></table></figure>



<h3 id="Operation描述方法"><a href="#Operation描述方法" class="headerlink" title="@Operation描述方法"></a>@Operation描述方法</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Operation(description = &quot;哈喽接口&quot;, method = &quot;哈喽接口&quot;, tags = &quot;hello接口&quot;, summary = &quot;哈喽接口&quot;)</span></span><br><span class="line">   <span class="meta">@GetMapping(&quot;/hello1&quot;)</span></span><br><span class="line">   <span class="keyword">public</span> String <span class="title function_">hello1</span><span class="params">(HttpServletRequest request)</span> &#123;</span><br><span class="line">       <span class="comment">//从请求对象中获取该用户的地区</span></span><br><span class="line">       <span class="type">Locale</span> <span class="variable">locale</span> <span class="operator">=</span> request.getLocale();</span><br><span class="line">       <span class="comment">//根据地区来配置显示内容</span></span><br><span class="line">       <span class="keyword">return</span> messageSource.getMessage(<span class="string">&quot;hello&quot;</span>, <span class="literal">null</span>, locale);</span><br><span class="line">   &#125;	</span><br></pre></td></tr></table></figure>

<h4 id="Parameter描述参数"><a href="#Parameter描述参数" class="headerlink" title="@Parameter描述参数"></a>@Parameter描述参数</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> String <span class="title function_">hello1</span><span class="params">(HttpServletRequest request,<span class="meta">@Parameter(description = &quot;name字段&quot;)</span> String name)</span></span><br></pre></td></tr></table></figure>

<h4 id="Schema描述bean类-也可以描述字段"><a href="#Schema描述bean类-也可以描述字段" class="headerlink" title="@Schema描述bean类 也可以描述字段"></a>@Schema描述bean类 也可以描述字段</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Schema(title = &quot;pig信息&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Pig</span> &#123;</span><br><span class="line">    <span class="meta">@Prefix(&quot;123&quot;)</span></span><br><span class="line">    <span class="meta">@Schema(title = &quot;猪的名字&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> String name;</span><br><span class="line">    <span class="meta">@NotNull</span></span><br><span class="line">    <span class="meta">@Schema(title = &quot;猪的年龄&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> Integer age;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h4 id="Docket给接口分组"><a href="#Docket给接口分组" class="headerlink" title="Docket给接口分组"></a>Docket给接口分组</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Bean</span></span><br><span class="line"><span class="keyword">public</span> GroupedOpenApi <span class="title function_">publicApi</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> GroupedOpenApi.builder()</span><br><span class="line">            .group(<span class="string">&quot;springshop-public&quot;</span>)</span><br><span class="line">            .pathsToMatch(<span class="string">&quot;/public/**&quot;</span>)</span><br><span class="line">            .build();</span><br><span class="line">&#125;</span><br><span class="line"><span class="meta">@Bean</span></span><br><span class="line"><span class="keyword">public</span> GroupedOpenApi <span class="title function_">adminApi</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> GroupedOpenApi.builder()</span><br><span class="line">            .group(<span class="string">&quot;springshop-admin&quot;</span>)</span><br><span class="line">            .pathsToMatch(<span class="string">&quot;/admin/**&quot;</span>)</span><br><span class="line">            .addMethodFilter(method -&gt; method.isAnnotationPresent(Admin.class))</span><br><span class="line">            .build();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="添加OpenAPI组件"><a href="#添加OpenAPI组件" class="headerlink" title="添加OpenAPI组件"></a>添加OpenAPI组件</h4><p>提供了一套用于构建和管理电子商务应用程序的 RESTful API。它可以用于创建、读取、更新和删除（CRUD）商店、产品、订单、用户等电子商务相关的资源</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Bean</span></span><br><span class="line"><span class="keyword">public</span> OpenAPI <span class="title function_">springShopOpenAPI</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">OpenAPI</span>()</span><br><span class="line">            .info(<span class="keyword">new</span> <span class="title class_">Info</span>().title(<span class="string">&quot;SpringShop API&quot;</span>)</span><br><span class="line">            .description(<span class="string">&quot;Spring shop sample application&quot;</span>)</span><br><span class="line">            .version(<span class="string">&quot;v0.0.1&quot;</span>)</span><br><span class="line">            .license(<span class="keyword">new</span> <span class="title class_">License</span>().name(<span class="string">&quot;Apache 2.0&quot;</span>).url(<span class="string">&quot;http://springdoc.org&quot;</span>)))</span><br><span class="line">            .externalDocs(<span class="keyword">new</span> <span class="title class_">ExternalDocumentation</span>()</span><br><span class="line">            .description(<span class="string">&quot;SpringShop Wiki Documentation&quot;</span>)</span><br><span class="line">            .url(<span class="string">&quot;https://springshop.wiki.github.org/docs&quot;</span>));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h2 id="远程调用RPC"><a href="#远程调用RPC" class="headerlink" title="远程调用RPC"></a>远程调用RPC</h2><p>RPC（Remote Procedure Call，远程过程调用）是一种通信协议，用于使一个进程（或线程）可以调用另一个进程（或线程）中的函数或方法，就像调用本地函数一样。它隐藏了底层网络通信的复杂性，使得分布式系统中的不同模块可以进行远程调用，实现分布式系统的协作</p>
<p>使用RPC，可以在<strong>微服务之间进行远程调用</strong>，<strong>实现服务间的通信</strong>。例如，假设有一个电子商务应用程序，拆分为以下几个微服务：用户服务、产品服务和订单服务。当用户下订单时，订单服务需要调用用户服务和产品服务来验证用户信息和获取产品信息。</p>
<h2 id="事务"><a href="#事务" class="headerlink" title="事务"></a>事务</h2><p>首先引入依赖</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-data-jpa<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p><strong>配置数据源</strong>：在<code>application.properties</code>或<code>application.yml</code>中配置数据源相关信息，如数据库连接URL、用户名、密码等</p>
<p>注解事务管理：在需要进行事务管理的方法上添加<code>@Transactional</code>注解。Spring Boot会自动为这些方法添加事务管理的逻辑</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Transactional</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">someMethod</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="comment">// 事务操作</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>配置事务管理器：Spring Boot会自动根据数据源的配置信息创建一个适合的事务管理器。如果需要自定义事务管理器，可以在配置类中添加<code>@Bean</code>注解来创建事务管理器。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">TransactionConfig</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> DataSource dataSource;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="keyword">public</span> PlatformTransactionManager <span class="title function_">transactionManager</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">DataSourceTransactionManager</span>(dataSource);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>通过以上步骤，Spring Boot会自动为被<code>@Transactional</code>注解标记的方法添加事务管理的逻辑。事务的传播行为、隔离级别、超时等属性可以通过在<code>@Transactional</code>注解中进行配置。</p>
<p>此外，Spring Boot还提供了一些其他的事务管理相关功能，如事务的回滚和异常处理。如果方法中抛出了未捕获的异常，Spring Boot会自动回滚事务。可以通过<code>@Transactional</code>注解的<code>rollbackFor</code>属性来配置需要回滚的异常类型</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Transactional(rollbackFor = &#123;Exception.class&#125;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">someMethod</span><span class="params">()</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">    <span class="comment">// 事务操作</span></span><br><span class="line">    <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Exception</span>(<span class="string">&quot;发生异常，事务回滚&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h2 id="Springboot发送邮件"><a href="#Springboot发送邮件" class="headerlink" title="Springboot发送邮件"></a>Springboot发送邮件</h2><h3 id="引入依赖"><a href="#引入依赖" class="headerlink" title="引入依赖"></a>引入依赖</h3><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-mail<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<h3 id="邮件配置"><a href="#邮件配置" class="headerlink" title="邮件配置"></a>邮件配置</h3><figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">server</span>:<span class="string"></span></span><br><span class="line">  <span class="attr">port</span>: <span class="string">80</span></span><br><span class="line"><span class="comment">#spring.mail.username，spring.mail.password填写自己的邮箱账号密码即可。</span></span><br><span class="line"><span class="attr">spring</span>:<span class="string"></span></span><br><span class="line">  <span class="attr">mail</span>:<span class="string"></span></span><br><span class="line">    <span class="attr">host</span>: <span class="string">smtp.163.com</span></span><br><span class="line">    <span class="attr">username</span>: <span class="string">你的账号</span></span><br><span class="line">    <span class="attr">password</span>: <span class="string">你的密码</span></span><br><span class="line">    <span class="attr">properties</span>:<span class="string"></span></span><br><span class="line">      <span class="attr">mail</span>:<span class="string"></span></span><br><span class="line">        <span class="attr">smtp</span>:<span class="string"></span></span><br><span class="line">          <span class="attr">auth</span>: <span class="string">true</span></span><br><span class="line">          <span class="attr">starttls</span>:<span class="string"></span></span><br><span class="line">            <span class="attr">enable</span>: <span class="string">true</span></span><br><span class="line">            <span class="attr">required</span>: <span class="string">true</span></span><br></pre></td></tr></table></figure>

<h3 id="发送简单的邮件"><a href="#发送简单的邮件" class="headerlink" title="发送简单的邮件"></a>发送简单的邮件</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@RequestMapping(&quot;/email&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">EmailController</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> JavaMailSender jms;</span><br><span class="line">    </span><br><span class="line">    <span class="meta">@Value(&quot;$&#123;spring.mail.username&#125;&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> String from;</span><br><span class="line">    </span><br><span class="line">    <span class="meta">@RequestMapping(&quot;sendSimpleEmail&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">sendSimpleEmail</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="type">SimpleMailMessage</span> <span class="variable">message</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">SimpleMailMessage</span>();</span><br><span class="line">            message.setFrom(from);</span><br><span class="line">            message.setTo(<span class="string">&quot;888888@qq.com&quot;</span>); <span class="comment">// 接收地址</span></span><br><span class="line">            message.setSubject(<span class="string">&quot;一封简单的邮件&quot;</span>); <span class="comment">// 标题</span></span><br><span class="line">            message.setText(<span class="string">&quot;使用Spring Boot发送简单邮件。&quot;</span>); <span class="comment">// 内容</span></span><br><span class="line">            jms.send(message);</span><br><span class="line">            <span class="keyword">return</span> <span class="string">&quot;发送成功&quot;</span>;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">            <span class="keyword">return</span> e.getMessage();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="发送HTML格式的邮件"><a href="#发送HTML格式的邮件" class="headerlink" title="发送HTML格式的邮件"></a>发送HTML格式的邮件</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@RequestMapping(&quot;/email&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">EmailController</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> JavaMailSender jms;</span><br><span class="line">    </span><br><span class="line">    <span class="meta">@Value(&quot;$&#123;spring.mail.username&#125;&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> String from;</span><br><span class="line">    </span><br><span class="line">    <span class="meta">@RequestMapping(&quot;sendHtmlEmail&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">sendHtmlEmail</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="type">MimeMessage</span> <span class="variable">message</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            message = jms.createMimeMessage();</span><br><span class="line">            <span class="type">MimeMessageHelper</span> <span class="variable">helper</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">MimeMessageHelper</span>(message, <span class="literal">true</span>);</span><br><span class="line">            helper.setFrom(from); </span><br><span class="line">            helper.setTo(<span class="string">&quot;888888@qq.com&quot;</span>); <span class="comment">// 接收地址</span></span><br><span class="line">            helper.setSubject(<span class="string">&quot;一封HTML格式的邮件&quot;</span>); <span class="comment">// 标题</span></span><br><span class="line">            <span class="comment">// 带HTML格式的内容</span></span><br><span class="line">            <span class="type">StringBuffer</span> <span class="variable">sb</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">StringBuffer</span>(<span class="string">&quot;&lt;p style=&#x27;color:#6db33f&#x27;&gt;使用Spring Boot发送HTML格式邮件。&lt;/p&gt;&quot;</span>);</span><br><span class="line">            helper.setText(sb.toString(), <span class="literal">true</span>);</span><br><span class="line">            jms.send(message);</span><br><span class="line">            <span class="keyword">return</span> <span class="string">&quot;发送成功&quot;</span>;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">            <span class="keyword">return</span> e.getMessage();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="发送带附件的邮件"><a href="#发送带附件的邮件" class="headerlink" title="发送带附件的邮件"></a>发送带附件的邮件</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@RequestMapping(&quot;/email&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">EmailController</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> JavaMailSender jms;</span><br><span class="line">    </span><br><span class="line">    <span class="meta">@Value(&quot;$&#123;spring.mail.username&#125;&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> String from;</span><br><span class="line">	</span><br><span class="line">    <span class="meta">@RequestMapping(&quot;sendAttachmentsMail&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">sendAttachmentsMail</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="type">MimeMessage</span> <span class="variable">message</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            message = jms.createMimeMessage();</span><br><span class="line">            <span class="type">MimeMessageHelper</span> <span class="variable">helper</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">MimeMessageHelper</span>(message, <span class="literal">true</span>);</span><br><span class="line">            helper.setFrom(from); </span><br><span class="line">            helper.setTo(<span class="string">&quot;888888@qq.com&quot;</span>); <span class="comment">// 接收地址</span></span><br><span class="line">            helper.setSubject(<span class="string">&quot;一封带附件的邮件&quot;</span>); <span class="comment">// 标题</span></span><br><span class="line">            helper.setText(<span class="string">&quot;详情参见附件内容！&quot;</span>); <span class="comment">// 内容</span></span><br><span class="line">            <span class="comment">// 传入附件</span></span><br><span class="line">            <span class="type">FileSystemResource</span> <span class="variable">file</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">FileSystemResource</span>(<span class="keyword">new</span> <span class="title class_">File</span>(<span class="string">&quot;src/main/resources/static/file/项目文档.docx&quot;</span>));</span><br><span class="line">            helper.addAttachment(<span class="string">&quot;项目文档.docx&quot;</span>, file);</span><br><span class="line">            jms.send(message);</span><br><span class="line">            <span class="keyword">return</span> <span class="string">&quot;发送成功&quot;</span>;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">            <span class="keyword">return</span> e.getMessage();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="发送带静态资源的邮件"><a href="#发送带静态资源的邮件" class="headerlink" title="发送带静态资源的邮件"></a>发送带静态资源的邮件</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@RequestMapping(&quot;/email&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">EmailController</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> JavaMailSender jms;</span><br><span class="line">    </span><br><span class="line">    <span class="meta">@Value(&quot;$&#123;spring.mail.username&#125;&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> String from;</span><br><span class="line">	</span><br><span class="line">    <span class="meta">@RequestMapping(&quot;sendInlineMail&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">sendInlineMail</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="type">MimeMessage</span> <span class="variable">message</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            message = jms.createMimeMessage();</span><br><span class="line">            <span class="type">MimeMessageHelper</span> <span class="variable">helper</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">MimeMessageHelper</span>(message, <span class="literal">true</span>);</span><br><span class="line">            helper.setFrom(from); </span><br><span class="line">            helper.setTo(<span class="string">&quot;888888@qq.com&quot;</span>); <span class="comment">// 接收地址</span></span><br><span class="line">            helper.setSubject(<span class="string">&quot;一封带静态资源的邮件&quot;</span>); <span class="comment">// 标题</span></span><br><span class="line">            helper.setText(<span class="string">&quot;&lt;html&gt;&lt;body&gt;博客图：&lt;img src=&#x27;cid:img&#x27;/&gt;&lt;/body&gt;&lt;/html&gt;&quot;</span>, <span class="literal">true</span>); <span class="comment">// 内容</span></span><br><span class="line">            <span class="comment">// 传入附件</span></span><br><span class="line">            <span class="type">FileSystemResource</span> <span class="variable">file</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">FileSystemResource</span>(<span class="keyword">new</span> <span class="title class_">File</span>(<span class="string">&quot;src/main/resources/static/img/sunshine.png&quot;</span>));</span><br><span class="line">            helper.addInline(<span class="string">&quot;img&quot;</span>, file); </span><br><span class="line">            jms.send(message);</span><br><span class="line">            <span class="keyword">return</span> <span class="string">&quot;发送成功&quot;</span>;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">            <span class="keyword">return</span> e.getMessage();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="使用模板发送邮件"><a href="#使用模板发送邮件" class="headerlink" title="使用模板发送邮件"></a>使用模板发送邮件</h3><p>在发送验证码等情况下可以创建一个邮件的模板，唯一的变量为验证码。这个例子中使用的模板解析引擎为Thymeleaf，所以首先引入Thymeleaf依赖：</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-thymeleaf<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>



<p>在template目录下创建一个<code>emailTemplate.html</code>模板：</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE <span class="keyword">html</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span> <span class="attr">lang</span>=<span class="string">&quot;zh&quot;</span> <span class="attr">xmlns:th</span>=<span class="string">&quot;http://www.thymeleaf.org&quot;</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">&quot;UTF-8&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">title</span>&gt;</span>模板<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">    您好，您的验证码为&#123;code&#125;，请在两分钟内使用完成操作。</span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure>



<p>发送模板邮件，本质上还是发送HTML邮件，只不过多了绑定变量的过程，详细如下所示：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@RequestMapping(&quot;/email&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">EmailController</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> JavaMailSender jms;</span><br><span class="line">    </span><br><span class="line">    <span class="meta">@Value(&quot;$&#123;spring.mail.username&#125;&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> String from;</span><br><span class="line">    </span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> TemplateEngine templateEngine;</span><br><span class="line">	</span><br><span class="line">    <span class="meta">@RequestMapping(&quot;sendTemplateEmail&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">sendTemplateEmail</span><span class="params">(String code)</span> &#123;</span><br><span class="line">        <span class="type">MimeMessage</span> <span class="variable">message</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            message = jms.createMimeMessage();</span><br><span class="line">            <span class="type">MimeMessageHelper</span> <span class="variable">helper</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">MimeMessageHelper</span>(message, <span class="literal">true</span>);</span><br><span class="line">            helper.setFrom(from); </span><br><span class="line">            helper.setTo(<span class="string">&quot;888888@qq.com&quot;</span>); <span class="comment">// 接收地址</span></span><br><span class="line">            helper.setSubject(<span class="string">&quot;邮件摸板测试&quot;</span>); <span class="comment">// 标题</span></span><br><span class="line">            <span class="comment">// 处理邮件模板</span></span><br><span class="line">            <span class="type">Context</span> <span class="variable">context</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Context</span>();</span><br><span class="line">            context.setVariable(<span class="string">&quot;code&quot;</span>, code);</span><br><span class="line">            <span class="type">String</span> <span class="variable">template</span> <span class="operator">=</span> templateEngine.process(<span class="string">&quot;emailTemplate&quot;</span>, context);</span><br><span class="line">            helper.setText(template, <span class="literal">true</span>);</span><br><span class="line">            jms.send(message);</span><br><span class="line">            <span class="keyword">return</span> <span class="string">&quot;发送成功&quot;</span>;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">            <span class="keyword">return</span> e.getMessage();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

  </div>
  
  
    
    <div class='footer'>
       <!-- 参考资料、相关资料等 -->
      
       <!-- 相关文章 -->
      
      <!-- 版权声明组件 -->
      
      <!-- 打赏组件 -->
      
    </div>
  
  
    


  <div class='article-meta' id="bottom">
    <div class='new-meta-box'>
      
        
          <div class="new-meta-item date" itemprop="dateModified" datetime="2024-02-17T12:39:33+08:00">
  <a class='notlink'>
    <i class="fa-solid fa-edit fa-fw" aria-hidden="true"></i>
    <p>更新于：Feb 17, 2024</p>
  </a>
</div>

        
      
        
          

        
      
        
          
  <div class="new-meta-item share -mob-share-list">
  <div class="-mob-share-list share-body">
    
      
        <a class="-mob-share-qq" title="" rel="external nofollow noopener noreferrer noopener"
          
          target="_blank" href="http://connect.qq.com/widget/shareqq/index.html?url=http://8.219.11.28/2024/02/23/%E5%89%8D%E5%90%8E%E7%AB%AF-SpringBoot/&title= - 欢迎来到我的个人博客~&summary="
          
          >
          
            <img src="https://unpkg.com/volantis-static@0.0.1654736714924/media/org.volantis/logo/128/qq.png" class="lazyload" data-srcset="https://unpkg.com/volantis-static@0.0.1654736714924/media/org.volantis/logo/128/qq.png" srcset="">
          
        </a>
      
    
      
        <a class="-mob-share-qzone" title="" rel="external nofollow noopener noreferrer noopener"
          
          target="_blank" href="https://sns.qzone.qq.com/cgi-bin/qzshare/cgi_qzshare_onekey?url=http://8.219.11.28/2024/02/23/%E5%89%8D%E5%90%8E%E7%AB%AF-SpringBoot/&title= - 欢迎来到我的个人博客~&summary="
          
          >
          
            <img src="https://unpkg.com/volantis-static@0.0.1654736714924/media/org.volantis/logo/128/qzone.png" class="lazyload" data-srcset="https://unpkg.com/volantis-static@0.0.1654736714924/media/org.volantis/logo/128/qzone.png" srcset="">
          
        </a>
      
    
      
        <a class="-mob-share-weibo" title="" rel="external nofollow noopener noreferrer noopener"
          
          target="_blank" href="http://service.weibo.com/share/share.php?url=http://8.219.11.28/2024/02/23/%E5%89%8D%E5%90%8E%E7%AB%AF-SpringBoot/&title= - 欢迎来到我的个人博客~&summary="
          
          >
          
            <img src="https://unpkg.com/volantis-static@0.0.1654736714924/media/org.volantis/logo/128/weibo.png" class="lazyload" data-srcset="https://unpkg.com/volantis-static@0.0.1654736714924/media/org.volantis/logo/128/weibo.png" srcset="">
          
        </a>
      
    
      
    
      
    
  </div>
</div>



        
      
    </div>
    <!-- Custom Files bottomMeta begin -->
    
    <!-- Custom Files bottomMeta end -->
  </div>


  
  

  
    <div class="prev-next">
      
        <a class='prev' href='/2024/02/23/%E5%89%8D%E5%90%8E%E7%AB%AF-Spring%E6%A1%86%E6%9E%B6%E8%AF%BE%E5%A0%82%E7%AC%94%E8%AE%B0/'>
          <p class='title'><i class="fa-solid fa-chevron-left" aria-hidden="true"></i>Feb 23, 2024</p>
          <p class='content'>Spring框架课堂笔记Spring概述，ioC ， DI ，AOP ，整合JDBC ，事务管理
1. Spring概述1.1 什么是框架？框架（Framework）：框（指其约束性）架（指其支...</p>
        </a>
      
      
        <a class='next' href='/2024/02/23/%E5%89%8D%E5%90%8E%E7%AB%AF-SpringFramework/'>
          <p class='title'>Feb 23, 2024<i class="fa-solid fa-chevron-right" aria-hidden="true"></i></p>
          <p class='content'>Spring6
1、概述1.1、Spring是什么？
Spring 是一款主流的 Java EE 轻量级开源框架 ，Spring 由“Spring 之父”Rod Johnson 提出并创立，其目...</p>
        </a>
      
    </div>
  
  <!-- Custom Files postEnd begin-->
  
  <!-- Custom Files postEnd end-->
</article>


  


  <article class="post white-box shadow floatable blur" id="comments">
    <span hidden>
      <meta itemprop="discussionUrl" content="/2024/02/23/%E5%89%8D%E5%90%8E%E7%AB%AF-SpringBoot/index.html#comments">
    </span>
    <p ct><i class='fa-solid fa-comments'></i> 评论</p>
    

    <div id="layoutHelper-comments"></div>

  </article>






</div>
<aside id='l_side' itemscope itemtype="http://schema.org/WPSideBar">
  

  
    
    
      
    
  


<div class="widget-sticky pjax">

  
  


  <section class="widget toc-wrapper desktop mobile " id="toc-div" >
    
  <header>
    
      <i class="fa-solid fa-list fa-fw" aria-hidden="true"></i><span class='name'>本文目录</span>
    
  </header>


    <div class='content'>
        <ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%88%9B%E5%BB%BAspringboot%E7%9A%84%E6%B5%81%E7%A8%8B"><span class="toc-text">创建springboot的流程:</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#1-maven-%E9%A1%B9%E7%9B%AE"><span class="toc-text">1.maven 项目</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#2-%E5%AF%BC%E5%85%A5%E9%9C%80%E8%A6%81%E7%9A%84%E5%9C%BA%E6%99%AF%E5%90%AF%E5%8A%A8%E5%99%A8"><span class="toc-text">2.导入需要的场景启动器</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#3-%E5%86%99%E5%AF%B9%E5%BA%94%E4%B8%9A%E5%8A%A1"><span class="toc-text">3.写对应业务</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#4-%E6%B5%8B%E8%AF%95"><span class="toc-text">4.测试</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#5-%E6%89%93%E5%8C%85"><span class="toc-text">5.打包</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#6-%E4%BB%BB%E6%84%8F%E8%BF%90%E8%A1%8C"><span class="toc-text">6.任意运行</span></a></li></ol></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%88%96%E8%80%85%E9%80%9A%E8%BF%87springinitailzer%E5%88%9B%E5%BB%BA"><span class="toc-text">或者通过springinitailzer创建</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%AE%80%E5%8C%96%E9%85%8D%E7%BD%AE"><span class="toc-text">**简化配置 **</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#1-%E7%9B%B4%E6%8E%A5%E5%9C%A8application-yml%E4%B8%AD%E6%94%B9"><span class="toc-text">1.直接在application.yml中改</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#2-application-yml%E4%B8%AD%E7%9A%84%E6%AF%8F%E4%B8%80%E4%B8%AA%E5%B1%9E%E6%80%A7-%E5%AF%B9%E5%BA%94%E7%9D%80%E6%9F%90%E4%B8%AA%E5%8C%85%E6%9F%90%E4%B8%AA%E7%B1%BB%E7%9A%84%E6%9F%90%E4%B8%AA%E5%AF%B9%E8%B1%A1%E7%9A%84%E5%B1%9E%E6%80%A7"><span class="toc-text">2.application.yml中的每一个属性 对应着某个包某个类的某个对象的属性**</span></a></li></ol></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%AC%AC%E4%B8%89%E6%96%B9jar%E5%8C%85"><span class="toc-text">**第三方jar包 **</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#ioc%E5%AE%B9%E5%99%A8"><span class="toc-text">ioc容器</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%BA%94%E7%94%A8%E5%90%AF%E5%8A%A8"><span class="toc-text">应用启动</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#1-Spring%E5%BA%94%E7%94%A8%E5%90%AF%E5%8A%A8%E7%9A%84%E6%AD%A5%E9%AA%A4"><span class="toc-text">1.Spring应用启动的步骤:</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#2-SpringApplication%E5%92%8CSpringContext%E7%9A%84%E5%8C%BA%E5%88%AB"><span class="toc-text">2.SpringApplication和SpringContext的区别</span></a></li></ol></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E9%BB%98%E8%AE%A4%E6%89%AB%E6%8F%8F"><span class="toc-text">默认扫描</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E8%87%AA%E5%8A%A8%E9%85%8D%E7%BD%AE"><span class="toc-text">自动配置</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%BB%84%E4%BB%B6%E6%B3%A8%E5%86%8C"><span class="toc-text">组件注册</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#1-%E9%80%9A%E8%BF%87-ComponentScan%E6%89%AB%E6%8F%8F%E6%8C%87%E5%AE%9A%E5%8C%85%EF%BC%8C%E5%B0%86%E5%8C%85%E4%B8%8B%E7%9A%84%E6%A0%87%E6%B3%A8-Controller%E3%80%81-Service%E3%80%81-Repository%E3%80%81-Component%E7%9A%84bean%E6%B3%A8%E5%86%8C%E5%88%B0IOC%E5%AE%B9%E5%99%A8%E4%B8%AD"><span class="toc-text">1.通过@ComponentScan扫描指定包，将包下的标注@Controller、@Service、@Repository、@Component的bean注册到IOC容器中</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#2-%E5%9C%A8%E9%85%8D%E7%BD%AE%E7%B1%BB-Configuration-%E4%B8%AD%E4%BD%BF%E7%94%A8-Bean%E6%B3%A8%E8%A7%A3%E5%B0%86%E6%96%B9%E6%B3%95%E8%BF%94%E5%9B%9E%E5%80%BC%E5%AF%B9%E8%B1%A1%E6%B3%A8%E5%86%8C%E5%88%B0IOC%E5%AE%B9%E5%99%A8%E4%B8%AD%EF%BC%8Cid%E9%BB%98%E8%AE%A4%E6%98%AF%E6%96%B9%E6%B3%95%E5%90%8D%E7%A7%B0%EF%BC%8C%E5%8F%AF%E9%80%9A%E8%BF%87value%E5%8F%82%E6%95%B0%E6%8C%87%E5%AE%9Aid"><span class="toc-text">2.在配置类(@Configuration)中使用@Bean注解将方法返回值对象注册到IOC容器中，id默认是方法名称，可通过value参数指定id</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#3-%E9%80%9A%E8%BF%87-Import%E6%B3%A8%E8%A7%A3%E5%B0%86Bean%E6%B3%A8%E5%86%8C%E5%88%B0IOC%E5%AE%B9%E5%99%A8%E4%B8%AD"><span class="toc-text">3.通过@Import注解将Bean注册到IOC容器中</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#4-%E5%B7%A5%E5%8E%82bean"><span class="toc-text">4.工厂bean</span></a></li></ol></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%9D%A1%E4%BB%B6%E6%B3%A8%E8%A7%A3"><span class="toc-text">条件注解</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#ConditionalOnClass-%E5%A6%82%E6%9E%9C%E5%AE%B9%E5%99%A8%E5%AD%98%E5%9C%A8Logger-class%E5%88%99%E8%A7%A6%E5%8F%91-%E4%B9%9F%E5%B0%B1%E6%98%AFpom%E9%87%8C%E6%9C%89"><span class="toc-text">@ConditionalOnClass 如果容器存在Logger.class则触发 也就是pom里有</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#ConditionalOnMissingClass-%E7%B1%BB%E8%B7%AF%E5%BE%84%E4%B8%8D%E5%AD%98%E5%9C%A8%E8%BF%99%E4%B8%AA%E7%B1%BB%E5%88%99%E8%A7%A6%E5%8F%91"><span class="toc-text">@ConditionalOnMissingClass 类路径不存在这个类则触发</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#ConditionalOnBean-%E5%A6%82%E6%9E%9C%E5%AE%B9%E5%99%A8%E4%B8%AD%E5%AD%98%E5%9C%A8%E8%BF%99%E4%B8%AAPig-bean%E7%BB%84%E4%BB%B6-%E5%88%99%E8%A7%A6%E5%8F%91"><span class="toc-text">@ConditionalOnBean 如果容器中存在这个Pig bean组件 则触发</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E6%B3%A8%E8%A7%A3%E5%BA%94%E7%94%A8%E5%9C%BA%E6%99%AF"><span class="toc-text">注解应用场景:</span></a></li></ol></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%B1%9E%E6%80%A7%E7%BB%91%E5%AE%9A%E6%B3%A8%E8%A7%A3"><span class="toc-text">属性绑定注解</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#ConfigurationProperties"><span class="toc-text">@ConfigurationProperties</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#EableConfigurationProperties"><span class="toc-text">@EableConfigurationProperties</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E4%BD%BF%E7%94%A8%E6%AD%A5%E9%AA%A4"><span class="toc-text">使用步骤:</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E5%9C%A8%E4%BD%BF%E7%94%A8-ConfigurationProperties%E6%97%B6%E9%9C%80%E8%A6%81%E5%85%88%E6%B3%A8%E5%86%8C%E7%BB%84%E4%BB%B6"><span class="toc-text">在使用@ConfigurationProperties时需要先注册组件</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E4%BD%BF%E7%94%A8-EableConfigurationProperties-%E4%B8%80%E8%88%AC%E7%94%A8%E4%BA%8E%E5%AF%BC%E5%85%A5%E7%AC%AC%E4%B8%89%E6%96%B9%E7%9A%84%E5%8C%85-%E8%A1%A8%E7%A4%BA%E5%85%81%E8%AE%B8%E9%85%8D%E7%BD%AE%E7%AC%AC%E4%B8%89%E5%8C%85%E7%9A%84%E9%85%8D%E7%BD%AE"><span class="toc-text">使用@EableConfigurationProperties 一般用于导入第三方的包  表示允许配置第三包的配置</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E7%9B%B8%E5%BD%93%E4%BA%8E-ConfigurationProperties-Import"><span class="toc-text">相当于@ConfigurationProperties + @Import</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#ConfigurationProperties-prefix-%E2%80%9Cuser%E2%80%9D-%E4%B9%9F%E5%8F%AF%E4%BB%A5%E7%9B%B4%E6%8E%A5%E6%94%BE%E5%9C%A8%E9%85%8D%E7%BD%AE%E7%B1%BB%E4%B8%AD"><span class="toc-text">@ConfigurationProperties(prefix &#x3D; “user”)也可以直接放在配置类中</span></a></li></ol></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%A4%8D%E6%9D%82%E5%AF%B9%E8%B1%A1%E7%9A%84yml%E8%A1%A8%E7%A4%BA"><span class="toc-text">复杂对象的yml表示</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%97%A5%E5%BF%97%E6%95%B4%E5%90%88%E5%8E%9F%E7%90%86"><span class="toc-text">日志整合原理</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#%E6%97%A5%E5%BF%97%E6%A0%BC%E5%BC%8F"><span class="toc-text">日志格式</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E6%97%B6%E9%97%B4-%E7%B2%BE%E7%A1%AE%E5%88%B0%E6%AF%AB%E7%A7%92-%E6%97%A5%E5%BF%97%E7%B1%BB%E5%9E%8B-%E6%97%A5%E5%BF%97%E8%BF%9B%E7%A8%8B-%E6%97%A5%E5%BF%97%E7%BA%BF%E7%A8%8B-%E8%BF%9B%E8%A1%8C%E7%9A%84java%E7%B1%BB-%E6%97%A5%E5%BF%97%E4%BF%A1%E6%81%AF"><span class="toc-text">时间 精确到毫秒  日志类型  日志进程  [日志线程]  进行的java类  日志信息</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E6%97%A5%E5%BF%97%E6%A0%BC%E5%BC%8F%E4%BF%AE%E6%94%B9"><span class="toc-text">日志格式修改</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E4%BD%BF%E7%94%A8%E6%97%A5%E5%BF%97"><span class="toc-text">使用日志</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E6%97%A5%E5%BF%97%E8%BE%93%E5%87%BA%E5%88%B0%E6%96%87%E4%BB%B6"><span class="toc-text">日志输出到文件</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E6%96%87%E4%BB%B6%E5%BD%92%E6%A1%A3%E4%B8%8E%E5%88%87%E5%89%B2"><span class="toc-text">文件归档与切割</span></a></li></ol></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%83%AD%E9%83%A8%E7%BD%B2"><span class="toc-text">热部署</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Web%E5%BC%80%E5%8F%91%E7%9B%B8%E5%85%B3"><span class="toc-text">Web开发相关</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%89%80%E6%9C%89%E7%9A%84MVC%E9%85%8D%E7%BD%AE-%E5%9C%A8WebMvcAutoConfiguration%E4%B8%AD"><span class="toc-text">所有的MVC配置 在WebMvcAutoConfiguration中</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Web%E8%87%AA%E5%8A%A8%E9%85%8D%E7%BD%AE%E5%8E%9F%E7%90%86"><span class="toc-text">Web自动配置原理</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#%E5%BC%95%E5%85%A5%E5%9C%BA%E6%99%AF"><span class="toc-text">引入场景</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E9%87%8C%E9%9D%A2%E5%8C%85%E5%90%AB%E4%BA%86-autoconfigure%E8%87%AA%E5%8A%A8%E9%85%8D%E7%BD%AE%E5%8A%9F%E8%83%BD"><span class="toc-text">里面包含了 autoconfigure自动配置功能:</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E5%9B%A0%E4%B8%BAspringboot%E5%BA%94%E7%94%A8%E5%BC%80%E5%90%AF%E4%BA%86%E8%87%AA%E5%8A%A8%E9%85%8D%E7%BD%AE"><span class="toc-text">因为springboot应用开启了自动配置</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E8%80%8C-EnableAutoConfiguration%E8%87%AA%E5%8A%A8%E9%85%8D%E7%BD%AE%E9%80%9A%E8%BF%87%E4%B8%80%E4%B8%AA%E7%B1%BB%E6%9D%A5%E6%89%B9%E9%87%8F%E5%AF%BC%E5%85%A5%E7%BB%84%E4%BB%B6"><span class="toc-text">而@EnableAutoConfiguration自动配置通过一个类来批量导入组件</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E5%8A%A0%E8%BD%BD-META-INF-spring-org-springframework-boot-autoconfigure-AutoConfiguration-imports-%E6%96%87%E4%BB%B6%E4%B8%AD%E9%85%8D%E7%BD%AE%E7%9A%84%E6%89%80%E6%9C%89%E7%BB%84%E4%BB%B6"><span class="toc-text">加载 META-INF&#x2F;spring&#x2F;org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件中配置的所有组件</span></a></li></ol></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#MvcConfigurer"><span class="toc-text">MvcConfigurer</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%95%B4%E5%90%88%E6%89%80%E6%9C%89%E9%80%82%E9%85%8D%E5%99%A8"><span class="toc-text">整合所有适配器</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%8B%A6%E6%88%AA%E5%99%A8-%E8%BF%87%E6%BB%A4%E5%99%A8"><span class="toc-text">拦截器 过滤器</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1-%E4%BD%BF%E7%94%A8%E6%8B%A6%E6%88%AA%E5%99%A8%EF%BC%9A"><span class="toc-text">1. 使用拦截器：</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%8B%A6%E6%88%AA%E5%99%A8%E7%9A%84%E8%A7%92%E8%89%B2%EF%BC%9A"><span class="toc-text">拦截器的角色：</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%B3%A8%E5%86%8C%E6%8B%A6%E6%88%AA%E5%99%A8%EF%BC%9A"><span class="toc-text">注册拦截器：</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-%E4%BD%BF%E7%94%A8%E8%BF%87%E6%BB%A4%E5%99%A8%EF%BC%9A"><span class="toc-text">2. 使用过滤器：</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E8%BF%87%E6%BB%A4%E5%99%A8%E7%9A%84%E8%A7%92%E8%89%B2%EF%BC%9A"><span class="toc-text">过滤器的角色：</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%B3%A8%E5%86%8C%E8%BF%87%E6%BB%A4%E5%99%A8%EF%BC%9A"><span class="toc-text">注册过滤器：</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%80%BB%E7%BB%93%EF%BC%9A"><span class="toc-text">总结：</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E8%87%AA%E5%AE%9A%E4%B9%89-%E8%BF%87%E6%BB%A4%E5%99%A8-%E6%8B%A6%E6%88%AA%E5%99%A8"><span class="toc-text">自定义 过滤器,拦截器</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E8%BF%87%E6%BB%A4%E5%99%A8"><span class="toc-text">过滤器</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#%E9%A6%96%E5%85%88%E9%80%9A%E8%BF%87servlet%E7%9A%84api%E6%9D%A5%E5%86%99%E4%B8%80%E4%B8%AA%E8%BF%87%E6%BB%A4%E5%99%A8"><span class="toc-text">首先通过servlet的api来写一个过滤器</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E7%84%B6%E5%90%8E%E4%BA%A4%E7%BB%99springboot%E7%AE%A1%E7%90%86-%E8%BF%99%E6%97%B6%E5%80%99-%E8%BF%87%E6%BB%A4%E5%99%A8%E8%87%AA%E5%8A%A8%E7%94%9F%E6%95%88"><span class="toc-text">然后交给springboot管理 这时候 过滤器自动生效</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%8B%A6%E6%88%AA%E5%99%A8"><span class="toc-text">拦截器</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#%E7%84%B6%E5%90%8E%E5%9C%A8MvcConfig%E6%B7%BB%E5%8A%A0"><span class="toc-text">然后在MvcConfig添加</span></a></li></ol></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%97%A5%E6%9C%9F%E6%A0%BC%E5%BC%8F%E5%8C%96%E8%BD%AC%E6%8D%A2%E5%99%A8"><span class="toc-text">日期格式化转换器</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#%E9%A6%96%E5%85%88%EF%BC%8C%E5%88%9B%E5%BB%BA%E8%87%AA%E5%AE%9A%E4%B9%89%E7%9A%84%E6%97%A5%E6%9C%9F%E6%A0%BC%E5%BC%8F%E5%8C%96%E5%99%A8%EF%BC%9A"><span class="toc-text">首先，创建自定义的日期格式化器：</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E7%84%B6%E5%90%8E%EF%BC%8C%E5%88%9B%E5%BB%BA%E8%87%AA%E5%AE%9A%E4%B9%89%E7%9A%84string-obj%E8%BD%AC%E6%8D%A2%E5%99%A8"><span class="toc-text">然后，创建自定义的string-obj转换器</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E5%9C%A8WebConfig-%E9%80%9A%E8%BF%87addFormatters%E6%96%B9%E6%B3%95%E6%B3%A8%E5%86%8C%E8%BF%99%E4%BA%9B%E8%87%AA%E5%AE%9A%E4%B9%89%E7%9A%84%E6%A0%BC%E5%BC%8F%E5%8C%96%E5%99%A8%E5%92%8C%E8%BD%AC%E6%8D%A2%E5%99%A8"><span class="toc-text">在WebConfig 通过addFormatters方法注册这些自定义的格式化器和转换器</span></a></li></ol></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%8F%82%E6%95%B0%E8%A7%A3%E6%9E%90%E5%99%A8"><span class="toc-text">参数解析器</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#AOP"><span class="toc-text">AOP</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#%E9%A6%96%E5%85%88%E5%AF%BC%E5%85%A5aop%E4%BE%9D%E8%B5%96"><span class="toc-text">首先导入aop依赖</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E8%A7%A6%E5%8F%91%E9%A1%BA%E5%BA%8F"><span class="toc-text">触发顺序</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E9%A6%96%E5%85%88%E7%A1%AE%E5%AE%9A%E5%88%87%E7%82%B9%E5%AF%B9%E8%B1%A1-Hellocontroller-%E7%84%B6%E5%90%8E%E7%BC%96%E5%86%99aop"><span class="toc-text">首先确定切点对象 Hellocontroller 然后编写aop</span></a></li></ol></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E8%87%AA%E5%AE%9A%E4%B9%89%E6%B3%A8%E8%A7%A3"><span class="toc-text">自定义注解</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%9B%BD%E9%99%85%E5%8C%96%E9%85%8D%E7%BD%AE"><span class="toc-text">国际化配置</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#MessageSource"><span class="toc-text">MessageSource</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#%E8%BF%99%E6%A0%B7%E5%81%9A%E4%BC%9A%E5%91%8A%E8%AF%89Spring-Boot%E5%8E%BB%E6%9F%A5%E6%89%BE%E5%90%8D%E4%B8%BAmessages-properties%E7%9A%84%E6%B6%88%E6%81%AF%E8%B5%84%E6%BA%90%E6%96%87%E4%BB%B6%EF%BC%8C%E5%B9%B6%E4%B8%94%E5%A6%82%E6%9E%9C%E6%89%BE%E4%B8%8D%E5%88%B0%E5%AF%B9%E5%BA%94%E7%9A%84%E6%B6%88%E6%81%AF%EF%BC%8C%E5%B0%B1%E4%BC%9A%E5%9B%9E%E9%80%80%E5%88%B0%E7%B3%BB%E7%BB%9F%E7%9A%84%E9%BB%98%E8%AE%A4%E8%AF%AD%E8%A8%80%E3%80%82"><span class="toc-text">这样做会告诉Spring Boot去查找名为messages.properties的消息资源文件，并且如果找不到对应的消息，就会回退到系统的默认语言。</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E5%9C%A8%E7%B1%BB%E4%B8%AD%E4%BD%BF%E7%94%A8"><span class="toc-text">在类中使用</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#controller%E4%BD%BF%E7%94%A8"><span class="toc-text">controller使用</span></a></li></ol></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Http%E7%BC%93%E5%AD%98"><span class="toc-text">Http缓存</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#%E9%85%8D%E7%BD%AE%E7%BC%93%E5%AD%98%E9%85%8D%E7%BD%AE"><span class="toc-text">配置缓存配置</span></a></li></ol></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E9%80%82%E9%85%8D%E5%A4%9A%E7%A7%8D%E6%95%B0%E6%8D%AE%E8%BF%94%E5%9B%9E"><span class="toc-text">适配多种数据返回</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1-%E9%BB%98%E8%AE%A4%E9%80%82%E9%85%8Djson"><span class="toc-text">1.默认适配json</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-%E9%80%9A%E8%BF%87%E8%AF%B7%E6%B1%82%E5%8F%82%E6%95%B0"><span class="toc-text">2.通过请求参数</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%A0%A1%E9%AA%8C%E5%99%A8"><span class="toc-text">校验器</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E9%BB%98%E8%AE%A4%E6%A0%A1%E9%AA%8C%E5%99%A8"><span class="toc-text">默认校验器</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E8%87%AA%E5%AE%9A%E4%B9%89%E6%A0%A1%E9%AA%8C%E8%A7%84%E5%88%99"><span class="toc-text">自定义校验规则</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Jackson%E5%B7%A5%E5%85%B7%E7%B1%BB"><span class="toc-text">Jackson工具类</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%A4%84%E7%90%86JSON%E5%BA%8F%E5%88%97%E5%8C%96%E5%92%8C%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96-%E4%BB%A5%E5%8F%8Ayaml"><span class="toc-text">处理JSON序列化和反序列化 以及yaml</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%A4%84%E7%90%86%E6%B6%88%E6%81%AF%E8%BD%AC%E6%8D%A2%E5%99%A8"><span class="toc-text">处理消息转换器</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%85%A8%E5%B1%80%E5%BC%82%E5%B8%B8%E5%A4%84%E7%90%86%E5%99%A8"><span class="toc-text">全局异常处理器</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E9%94%99%E8%AF%AF%E4%BF%A1%E6%81%AF%E6%96%B0%E7%9A%84%E8%BF%94%E5%9B%9E%E4%BF%A1%E6%81%AF"><span class="toc-text">错误信息新的返回信息</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%87%BD%E6%95%B0%E5%BC%8FWeb%E5%A4%84%E7%90%86%E6%96%B9%E5%BC%8F"><span class="toc-text">函数式Web处理方式</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Spring%E5%9F%BA%E7%A1%80%E9%85%8D%E7%BD%AE"><span class="toc-text">Spring基础配置</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#1-Spring%E5%90%AF%E5%8A%A8banner%E7%9A%84%E8%87%AA%E5%AE%9A%E4%B9%89%E8%AE%BE%E7%BD%AE"><span class="toc-text">1.Spring启动banner的自定义设置</span></a></li></ol></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Spring%E6%95%B4%E5%90%88SSM"><span class="toc-text">Spring整合SSM</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E8%A7%A3%E5%86%B3%E4%B8%A4%E8%80%85%E5%86%B2%E7%AA%81"><span class="toc-text">解决两者冲突</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%95%B4%E5%90%88%E5%85%B6%E4%BB%96%E6%95%B0%E6%8D%AE%E6%BA%90"><span class="toc-text">整合其他数据源</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E4%BD%BF%E7%94%A8MybatisX%E5%BF%AB%E9%80%9F%E5%88%9B%E5%BB%BA"><span class="toc-text">使用MybatisX快速创建</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%88%86%E9%A1%B5%E6%8F%92%E4%BB%B6"><span class="toc-text">分页插件</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E9%80%BB%E8%BE%91%E5%88%A0%E9%99%A4"><span class="toc-text">逻辑删除</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Spring%E6%95%B4%E5%90%88redis"><span class="toc-text">Spring整合redis</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E9%BB%98%E8%AE%A4Redis"><span class="toc-text">默认Redis</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#redis%E5%AE%9A%E5%88%B6%E5%8C%96%E9%85%8D%E7%BD%AE"><span class="toc-text">redis定制化配置</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#redis%E4%BE%9D%E8%B5%96"><span class="toc-text">redis依赖</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%BC%BA%E5%A4%A7%E5%B7%A5%E5%85%B7SpringCache"><span class="toc-text">强大工具SpringCache</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Spring%E5%A4%96%E9%83%A8%E5%8C%96%E9%85%8D%E7%BD%AE"><span class="toc-text">Spring外部化配置</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E9%85%8D%E7%BD%AE%E4%BC%98%E5%85%88%E7%BA%A7"><span class="toc-text">配置优先级</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E4%BD%BF%E7%94%A8application-properties%E6%88%96application-yml%E6%96%87%E4%BB%B6%EF%BC%9A"><span class="toc-text">使用application.properties或application.yml文件：</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E4%BD%BF%E7%94%A8%E5%A4%96%E9%83%A8%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6"><span class="toc-text">使用外部配置文件</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Spring-%E2%80%93-Junit-%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95"><span class="toc-text">Spring  – Junit 单元测试</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#DisplayName-%E6%8C%87%E5%AE%9A%E6%B5%8B%E8%AF%95%E5%8D%95%E5%85%83%E7%9A%84%E5%90%8D%E5%AD%97"><span class="toc-text">@DisplayName 指定测试单元的名字</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#BeforeEach-BeforeAll-AfterAll-AfterEach"><span class="toc-text">@BeforeEach @BeforeAll @AfterAll @AfterEach</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Test%E6%8F%90%E4%BE%9B%E7%9A%84%E6%96%AD%E8%A8%80%E5%B7%A5%E5%85%B7Assertions"><span class="toc-text">Test提供的断言工具Assertions</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%8F%82%E6%95%B0%E5%8C%96%E6%B5%8B%E8%AF%95"><span class="toc-text">参数化测试</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%B8%8A%E4%B8%8B%E6%96%87"><span class="toc-text">上下文</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%B9%9D%E5%A4%A7%E4%BA%8B%E4%BB%B6%E5%92%8C%E6%8E%A2%E9%92%88"><span class="toc-text">九大事件和探针</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%BA%8B%E4%BB%B6%E7%9B%91%E5%90%AC%E6%9C%BA%E5%88%B6"><span class="toc-text">事件监听机制</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E7%94%A8%E4%BA%8E%E7%9B%91%E5%90%AC%E6%9F%90%E4%B8%AA%E4%BA%8B%E4%BB%B6-%E5%81%9A%E6%9F%90%E4%BA%8B%E6%83%85-%E5%8F%AF%E4%BB%A5%E7%94%A8%E6%9D%A5%E5%8A%A0%E9%9C%80%E6%B1%82%E7%9A%84%E6%97%B6%E5%80%99%E7%94%A8"><span class="toc-text">用于监听某个事件 做某事情 可以用来加需求的时候用</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%85%B7%E4%BD%93%E4%BE%8B%E5%AD%90-%E4%BB%A5%E7%94%A8%E6%88%B7%E6%B3%A8%E5%86%8C%E5%90%8E%E5%8F%91%E9%80%81%E6%AC%A2%E8%BF%8E%E9%82%AE%E4%BB%B6%E4%B8%BA%E4%BE%8B"><span class="toc-text">具体例子 以用户注册后发送欢迎邮件为例</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%86%8D%E6%9D%A5%E4%B8%80%E4%B8%AA%E4%BE%8B%E5%AD%90-%E7%8E%B0%E5%9C%A8%E5%B7%B2%E7%BB%8F%E5%86%99%E5%A5%BD%E4%BA%86%E8%AE%B0%E5%BD%95%E4%BF%A1%E6%81%AF%E5%92%8C%E5%8F%91%E9%80%81%E9%82%AE%E4%BB%B6%E7%9A%84%E4%B8%9A%E5%8A%A1%EF%BC%8C%E4%BD%86%E6%98%AF%E8%BF%98%E8%A6%81%E5%8A%A0%E4%B8%80%E4%B8%AA%E5%BD%93%E7%94%A8%E6%88%B7%E7%99%BB%E9%99%86%E6%97%B6%EF%BC%8C%E7%9B%91%E5%90%AC%E4%BA%8B%E4%BB%B6%E7%84%B6%E5%90%8E%E7%BB%99%E7%99%BB%E5%BD%95%E7%94%A8%E6%88%B7%E5%8F%91%E9%80%81%E4%BC%98%E6%83%A0%E5%88%B8%E7%9A%84%E4%B8%9A%E5%8A%A1"><span class="toc-text">再来一个例子:现在已经写好了记录信息和发送邮件的业务，但是还要加一个当用户登陆时，监听事件然后给登录用户发送优惠券的业务</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#controller-service"><span class="toc-text">controller service:</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E9%A6%96%E5%85%88%E7%BC%96%E5%86%99%E4%BA%8B%E4%BB%B6-%E4%B9%9F%E5%B0%B1%E6%98%AF%E7%99%BB%E5%BD%95%E4%BA%8B%E4%BB%B6%E9%9C%80%E8%A6%81%E7%BB%A7%E6%89%BFspring%E7%9A%84event%E7%B1%BB"><span class="toc-text">首先编写事件 也就是登录事件需要继承spring的event类</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%84%B6%E5%90%8E%E5%86%99%E4%B8%80%E4%B8%AA%E7%BB%A7%E6%89%BF%E4%BA%86spring%E5%8F%91%E5%B8%83%E4%BA%8B%E4%BB%B6%E7%B1%BB%E7%9A%84%E8%87%AA%E5%AE%9A%E4%B9%89%E4%BA%8B%E4%BB%B6%E5%8F%91%E5%B8%83%E7%B1%BB-%E6%96%B9%E4%BE%BF%E7%9B%91%E5%90%AC%E5%99%A8%E7%9B%91%E5%90%AC"><span class="toc-text">然后写一个继承了spring发布事件类的自定义事件发布类 方便监听器监听</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%86%99%E4%B8%80%E4%B8%AA%E7%9B%91%E5%90%AC%E4%BA%8B%E4%BB%B6%E7%9A%84%E7%B1%BBLoginEventListener-%E5%8A%A0%E4%BA%86-EventListener%E5%90%8E-%E5%9C%A8%E5%AE%B9%E5%99%A8%E4%B8%AD%E5%8F%AF%E4%BB%A5%E8%87%AA%E5%8A%A8%E7%9B%91%E5%90%AC%E4%BA%8B%E4%BB%B6"><span class="toc-text">写一个监听事件的类LoginEventListener 加了@EventListener后 在容器中可以自动监听事件</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%84%B6%E5%90%8E%E5%9C%A8controller%E4%B8%AD-%E5%88%9B%E5%BB%BA%E4%BA%8B%E4%BB%B6%E5%AF%B9%E8%B1%A1-%E6%B3%A8%E5%85%A5%E4%BA%8B%E4%BB%B6%E5%8F%91%E5%B8%83%E5%AF%B9%E8%B1%A1"><span class="toc-text">然后在controller中 创建事件对象 注入事件发布对象</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%8E%A2%E9%92%88%E6%9C%BA%E5%88%B6"><span class="toc-text">探针机制</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E8%87%AA%E5%AE%9A%E4%B9%89Swagger"><span class="toc-text">自定义Swagger</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E9%85%8D%E7%BD%AE"><span class="toc-text">配置</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Tag%E6%8F%8F%E8%BF%B0%E6%8E%A5%E5%8F%A3%E6%96%87%E6%A1%A3%E7%9A%84%E7%B1%BB"><span class="toc-text">@Tag描述接口文档的类</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Operation%E6%8F%8F%E8%BF%B0%E6%96%B9%E6%B3%95"><span class="toc-text">@Operation描述方法</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#Parameter%E6%8F%8F%E8%BF%B0%E5%8F%82%E6%95%B0"><span class="toc-text">@Parameter描述参数</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Schema%E6%8F%8F%E8%BF%B0bean%E7%B1%BB-%E4%B9%9F%E5%8F%AF%E4%BB%A5%E6%8F%8F%E8%BF%B0%E5%AD%97%E6%AE%B5"><span class="toc-text">@Schema描述bean类 也可以描述字段</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Docket%E7%BB%99%E6%8E%A5%E5%8F%A3%E5%88%86%E7%BB%84"><span class="toc-text">Docket给接口分组</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%B7%BB%E5%8A%A0OpenAPI%E7%BB%84%E4%BB%B6"><span class="toc-text">添加OpenAPI组件</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E8%BF%9C%E7%A8%8B%E8%B0%83%E7%94%A8RPC"><span class="toc-text">远程调用RPC</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%BA%8B%E5%8A%A1"><span class="toc-text">事务</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Springboot%E5%8F%91%E9%80%81%E9%82%AE%E4%BB%B6"><span class="toc-text">Springboot发送邮件</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%BC%95%E5%85%A5%E4%BE%9D%E8%B5%96"><span class="toc-text">引入依赖</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E9%82%AE%E4%BB%B6%E9%85%8D%E7%BD%AE"><span class="toc-text">邮件配置</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%8F%91%E9%80%81%E7%AE%80%E5%8D%95%E7%9A%84%E9%82%AE%E4%BB%B6"><span class="toc-text">发送简单的邮件</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%8F%91%E9%80%81HTML%E6%A0%BC%E5%BC%8F%E7%9A%84%E9%82%AE%E4%BB%B6"><span class="toc-text">发送HTML格式的邮件</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%8F%91%E9%80%81%E5%B8%A6%E9%99%84%E4%BB%B6%E7%9A%84%E9%82%AE%E4%BB%B6"><span class="toc-text">发送带附件的邮件</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%8F%91%E9%80%81%E5%B8%A6%E9%9D%99%E6%80%81%E8%B5%84%E6%BA%90%E7%9A%84%E9%82%AE%E4%BB%B6"><span class="toc-text">发送带静态资源的邮件</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E4%BD%BF%E7%94%A8%E6%A8%A1%E6%9D%BF%E5%8F%91%E9%80%81%E9%82%AE%E4%BB%B6"><span class="toc-text">使用模板发送邮件</span></a></li></ol></li></ol>
    </div>
  </section>

  

</div>


<!-- 没有 pjax 占位会报错 万恶的 pjax -->

  <div class="pjax">
    <!-- pjax占位 -->
  </div>

  <div class="pjax">
    <!-- pjax占位 -->
  </div>

  <div class="pjax">
    <!-- pjax占位 -->
  </div>

  <div class="pjax">
    <!-- pjax占位 -->
  </div>

  <div class="pjax">
    <!-- pjax占位 -->
  </div>

  <div class="pjax">
    <!-- pjax占位 -->
  </div>

  <div class="pjax">
    <!-- pjax占位 -->
  </div>

  <div class="pjax">
    <!-- pjax占位 -->
  </div>

  <!-- Custom Files side begin -->
  
  <!-- Custom Files side end -->
</aside>



          <!--此文件用来存放一些不方便取值的变量-->
<!--思路大概是将值藏到重加载的区域内-->

<pjax>
<script>
  window.pdata={}
  pdata.ispage=false;
  pdata.commentPath="";
  pdata.commentPlaceholder="";
  pdata.commentConfig={};
  //  see: /layout/_partial/scripts/_ctrl/coverCtrl.ejs
  
    // header
    var l_header=document.getElementById("l_header");
    
    l_header.classList.add("show");
    
    
      // cover
      var cover_wrapper=document.querySelector('#l_cover .cover-wrapper');
      var scroll_down=document.getElementById('scroll-down');
      cover_wrapper.id="none";
      cover_wrapper.style.display="none";
      scroll_down.style.display="none";
    
  
</script>
</pjax>
        </div>
        
  
  <footer class="footer clearfix"  itemscope itemtype="http://schema.org/WPFooter">
    <br><br>
    
      
        <div class="aplayer-container">
          


        </div>
      
    
      
        <br>
        <div class="social-wrapper" itemprop="about" itemscope itemtype="http://schema.org/Thing">
          
            
          
            
          
            
          
        </div>
      
    
      
        <div><p>Blog content follows the <a target="_blank" rel="noopener" href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en">Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0) License</a></p>
</div>
      
    
      
        
          <div><p><span id="lc-sv">本站总访问量为 <span id='number'><i class="fa-solid fa-loader fa-spin fa-fw" aria-hidden="true"></i></span> 次</span> <span id="lc-uv">访客数为 <span id='number'><i class="fa-solid fa-loader fa-spin fa-fw" aria-hidden="true"></i></span> 人</span></p>
</div>
        
      
    
      
        Use
        <a href="https://github.com/volantis-x/hexo-theme-volantis/#5.8.0" target="_blank" class="codename">Volantis</a>
        as theme
      
    
      
        <div class='copyright'>
        <p><a href="/">Copyright © since 2017 XXX</a></p>

        </div>
      
    
    <!-- Custom Files footer begin-->
    
    <!-- Custom Files footer end-->
  </footer>


        <a id="s-top" class="fa-solid fa-arrow-up fa-fw" href="/" onclick="return false;" title="top"></a>
      </div>
    </div>
    <div>
      <script>
  /******************** volantis.dom ********************************/
  // 页面选择器 将dom对象缓存起来 see: /source/js/app.js etc.
  volantis.dom.bodyAnchor = volantis.dom.$(document.getElementById("safearea")); // 页面主体
  volantis.dom.topBtn = volantis.dom.$(document.getElementById('s-top')); // 向上
  volantis.dom.wrapper = volantis.dom.$(document.getElementById('wrapper')); // 整个导航栏
  volantis.dom.coverAnchor = volantis.dom.$(document.querySelector('#l_cover .cover-wrapper')); // 1个
  volantis.dom.switcher = volantis.dom.$(document.querySelector('#l_header .switcher .s-search')); // 搜索按钮   移动端 1个
  volantis.dom.header = volantis.dom.$(document.getElementById('l_header')); // 移动端导航栏
  volantis.dom.search = volantis.dom.$(document.querySelector('#l_header .m_search')); // 搜索框 桌面端 移动端 1个
  volantis.dom.mPhoneList = volantis.dom.$(document.querySelectorAll('#l_header .m-phone .list-v')); //  手机端 子菜单 多个
</script>

<script>
  
  volantis.css("https://unpkg.com/volantis-static@0.0.1654736714924/libs/@fortawesome/fontawesome-free/css/all.min.css");
  
  
  
</script>

<!-- required -->


<!-- internal -->

<script src="/js/app.js"></script>






<!-- rightmenu要在darkmode之前（ToggleButton） darkmode要在comments之前（volantis.dark.push）-->



<script>
  function loadIssuesJS() {
    
      const sites_api = document.getElementById('sites-api');
      if (sites_api != undefined && typeof SitesJS === 'undefined') {
        volantis.js("/js/plugins/tags/sites.js")
      }
    
    
      const friends_api = document.getElementById('friends-api');
      if (friends_api != undefined && typeof FriendsJS === 'undefined') {
        volantis.js("/js/plugins/tags/friends.js")
      }
    
    
      const contributors_api = document.getElementById('contributors-api');
      if (contributors_api != undefined && typeof ContributorsJS === 'undefined') {
        volantis.js("/js/plugins/tags/contributors.js")
      }
    
  };
  loadIssuesJS()
  volantis.pjax.push(()=>{
    loadIssuesJS();
  })

</script>




  <script defer src="https://unpkg.com/volantis-static@0.0.1654736714924/libs/vanilla-lazyload/dist/lazyload.min.js"></script>
<script>
  // https://www.npmjs.com/package/vanilla-lazyload
  // Set the options globally
  // to make LazyLoad self-initialize
  window.lazyLoadOptions = {
    elements_selector: ".lazyload",
    threshold: 0
  };
  // Listen to the initialization event
  // and get the instance of LazyLoad
  window.addEventListener(
    "LazyLoad::Initialized",
    function (event) {
      window.lazyLoadInstance = event.detail.instance;
    },
    false
  );
  document.addEventListener('DOMContentLoaded', function () {
    lazyLoadInstance.update();
  });
  document.addEventListener('pjax:complete', function () {
    lazyLoadInstance.update();
  });
</script>




  

<script>
  window.FPConfig = {
	delay: 0,
	ignoreKeywords: ["#"],
	maxRPS: 6,
	hoverDelay: 0
  };
</script>
<script defer src="https://unpkg.com/volantis-static@0.0.1654736714924/libs/flying-pages/flying-pages.min.js"></script>









      <script>
  volantis.layoutHelper("comments",`<div id="giscus_container"></div>`)

  volantis.giscus = {};

  function check_giscus() {
    if (volantis.dark.mode === "dark") {
      volantis.giscus.Theme = 'dark';
    } else {
      volantis.giscus.Theme = 'light';
    }

    return document.getElementById("giscus_container");
  }

  function pjax_giscus() {
    const HEAD = check_giscus();
    if (!HEAD) return;
    let cfg = Object.assign({"theme":{"light":"light","dark":"dark"}},pdata.commentConfig)
    const script = document.createElement('script');
    script.setAttribute('src', 'https://giscus.app/client.js');
    Object.keys(cfg).forEach(k=>{
      if (k != "theme") {
        script.setAttribute('data-'+k, cfg[k]);
      }
    })
    script.setAttribute('data-theme', volantis.giscus.Theme);
    script.setAttribute('crossorigin', "anonymous");
    HEAD.appendChild(script);
  }

  function dark_giscus() {
    const HEAD = check_giscus();
    if (!HEAD) return;

    const message = {
      setConfig: {
        theme: volantis.giscus.Theme
      }
    };
    const giscusIframe = document.querySelector('iframe.giscus-frame');
    giscusIframe.contentWindow.postMessage({ giscus: message }, 'https://giscus.app');
  }
  pjax_giscus();
  volantis.pjax.push(pjax_giscus);
  volantis.dark.push(dark_giscus);
</script>

    





<!-- optional -->

  <script>
  const SearchServiceDataPathRoot = ("/" || "/").endsWith("/") ?
    "/" || "/" :
    "//" || "/";
  const SearchServiceDataPath = SearchServiceDataPathRoot + "content.json";

  function loadSearchScript() {
    // see: layout/_partial/scripts/_ctrl/cdnCtrl.ejs
    return volantis.js("/js/search/hexo.js");
  }

  function loadSearchService() {
    loadSearchScript();
    document.querySelectorAll(".input.u-search-input").forEach((e) => {
      e.removeEventListener("focus", loadSearchService, false);
    });

    document.querySelectorAll(".u-search-form").forEach((e) => {
      e.addEventListener("submit", (event) => {
        event.preventDefault();
      }, false);
    });
  }

  // 打开并搜索 字符串 s
  function OpenSearch(s) {
    if (typeof SearchService === 'undefined')
      loadSearchScript().then(() => {
        SearchService.setQueryText(s);
        SearchService.search();
      });
    else {
      SearchService.setQueryText(s);
      SearchService.search();
    }
  }

  // 访问含有 ?s=xxx  的链接时打开搜索 // 与搜索引擎 structured data 相关: /scripts/helpers/structured-data/lib/config.js
  if (window.location.search && /^\?s=/g.test(window.location.search)) {
    let queryText = decodeURI(window.location.search)
      .replace(/\ /g, "-")
      .replace(/^\?s=/g, "");
    OpenSearch(queryText);
  }

  // 搜索输入框获取焦点时加载搜索
  document.querySelectorAll(".input.u-search-input").forEach((e) => {
    e.addEventListener("focus", loadSearchService, false);
  });
</script>







  <script>



  function pjax_highlightjs_copyCode(){
    if (!(document.querySelector(".highlight .code pre") ||
      document.querySelector(".article pre code"))) {
      return;
    }
    VolantisApp.utilCopyCode(".highlight .code pre, .article pre code")
  }
  volantis.requestAnimationFrame(pjax_highlightjs_copyCode)
  volantis.pjax.push(pjax_highlightjs_copyCode)

</script>












  <script>
  function load_swiper() {
    if (!document.querySelectorAll(".swiper-container")[0]) return;
    volantis.css("https://unpkg.com/volantis-static@0.0.1654736714924/libs/swiper/swiper-bundle.min.css");
    volantis.js("https://unpkg.com/volantis-static@0.0.1654736714924/libs/swiper/swiper-bundle.min.js").then(() => {
      pjax_swiper();
    });
  }

  load_swiper();

  function pjax_swiper() {
    volantis.swiper = new Swiper('.swiper-container', {
      slidesPerView: 'auto',
      spaceBetween: 8,
      centeredSlides: true,
      loop: true,
      pagination: {
        el: '.swiper-pagination',
        clickable: true,
      },
      navigation: {
        nextEl: '.swiper-button-next',
        prevEl: '.swiper-button-prev',
      },
    });
  }

  volantis.pjax.push(() => {
    if (!document.querySelectorAll(".swiper-container")[0]) return;
    if (typeof volantis.swiper === "undefined") {
      load_swiper();
    } else {
      pjax_swiper();
    }
  });
</script>


<!-- pjax 标签必须存在于所有页面 否则 pjax error -->
<pjax>

</pjax>

<script>
  function listennSidebarTOC() {
    const navItems = document.querySelectorAll(".toc li");
    if (!navItems.length) return;
    let targets = []
    const sections = [...navItems].map((element) => {
      const link = element.querySelector(".toc-link");
      const target = document.getElementById(
        decodeURI(link.getAttribute("href")).replace("#", "")
      );
      targets.push(target)
      // 解除 a 标签 href 的 锚点定位, a 标签 href 的 锚点定位 会随机启用?? 产生错位???
      link.setAttribute("onclick","return false;")
      link.setAttribute("toc-action","toc-"+decodeURI(link.getAttribute("href")).replace("#", ""))
      link.setAttribute("href","/")
      // 配置 点击 触发新的锚点定位
      link.addEventListener("click", (event) => {
        event.preventDefault();
        // 这里的 addTop 是通过错位使得 toc 自动展开.
        volantis.scroll.to(target,{addTop: 5, observer:true})
        // Anchor id
        history.pushState(null, document.title, "#" + target.id);
      });
      return target;
    });

    function activateNavByIndex(target) {
      if (target.classList.contains("active-current")) return;

      document.querySelectorAll(".toc .active").forEach((element) => {
        element.classList.remove("active", "active-current");
      });
      target.classList.add("active", "active-current");
      let parent = target.parentNode;
      while (!parent.matches(".toc")) {
        if (parent.matches("li")) parent.classList.add("active");
        parent = parent.parentNode;
      }
    }

    // 方案一：
    volantis.activateNavIndex=0
    activateNavByIndex(navItems[volantis.activateNavIndex])
    volantis.scroll.push(()=>{
      if (targets[0].getBoundingClientRect().top >= 0) {
        volantis.activateNavIndex = 0
      }else if (targets[targets.length-1].getBoundingClientRect().top < 0) {
        volantis.activateNavIndex = targets.length-1
      } else {
        for (let index = 0; index < targets.length; index++) {
          const target0 = targets[index];
          const target1 = targets[(index+1)%targets.length];
          if (target0.getBoundingClientRect().top < 0&&target1.getBoundingClientRect().top >= 0) {
            volantis.activateNavIndex=index
            break;
          }
        }
      }
      activateNavByIndex(navItems[volantis.activateNavIndex])
    })

    // 方案二：
    // IntersectionObserver 不是完美精确到像素级别 也不是低延时性的
    // function findIndex(entries) {
    //   let index = 0;
    //   let entry = entries[index];
    //   if (entry.boundingClientRect.top > 0) {
    //     index = sections.indexOf(entry.target);
    //     return index === 0 ? 0 : index - 1;
    //   }
    //   for (; index < entries.length; index++) {
    //     if (entries[index].boundingClientRect.top <= 0) {
    //       entry = entries[index];
    //     } else {
    //       return sections.indexOf(entry.target);
    //     }
    //   }
    //   return sections.indexOf(entry.target);
    // }
    // function createIntersectionObserver(marginTop) {
    //   marginTop = Math.floor(marginTop + 10000);
    //   let intersectionObserver = new IntersectionObserver(
    //     (entries, observe) => {
    //       let scrollHeight = document.documentElement.scrollHeight;
    //       if (scrollHeight > marginTop) {
    //         observe.disconnect();
    //         createIntersectionObserver(scrollHeight);
    //         return;
    //       }
    //       let index = findIndex(entries);
    //       activateNavByIndex(navItems[index]);
    //     }, {
    //       rootMargin: marginTop + "px 0px -100% 0px",
    //       threshold: 0,
    //     }
    //   );
    //   sections.forEach((element) => {
    //     element && intersectionObserver.observe(element);
    //   });
    // }
    // createIntersectionObserver(document.documentElement.scrollHeight);
  }

  document.addEventListener("DOMContentLoaded", ()=>{
    volantis.requestAnimationFrame(listennSidebarTOC)
  });
  document.addEventListener("pjax:success", ()=>{
    volantis.requestAnimationFrame(listennSidebarTOC)
  });
</script>



<script>
  document.onreadystatechange = function () {
    if (document.readyState == 'complete') {
      // 页面加载完毕 样式加载失败，或是当前网速慢，或是开启了省流模式
      const { saveData, effectiveType } = navigator.connection || navigator.mozConnection || navigator.webkitConnection || {}
      if (getComputedStyle(document.querySelector("#safearea"), null)["display"] == "none" || saveData || /2g/.test(effectiveType)) {
        document.querySelectorAll(".reveal").forEach(function (e) {
          e.style["opacity"] = "1";
        });
        document.querySelector("#safearea").style["display"] = "block";
      }
    }
  }
</script>


  <script type="application/ld+json">[{"@context":"http://schema.org","@type":"Organization","name":"欢迎来到我的个人博客~","url":"http://8.219.11.28/","logo":{"@type":"ImageObject","url":"https://unpkg.com/volantis-static@0.0.1654736714924/media/org.volantis/blog/favicon/android-chrome-192x192.png","width":192,"height":192}},{"@context":"http://schema.org","@type":"Person","name":"天明","image":{"@type":"ImageObject","url":"https://unpkg.com/volantis-static@0.0.1654736714924/media/org.volantis/blog/favicon/android-chrome-192x192.png"},"url":"http://8.219.11.28/","sameAs":["https://github.com/volantis-x"],"description":"这些技术大部分是自己总结的，非官方"},{"@context":"http://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"http://8.219.11.28/","name":"欢迎来到我的个人博客~"}},{"@type":"ListItem","position":3,"item":{"@id":"http://8.219.11.28/2024/02/23/前后端-SpringBoot/"}}]},{"@context":"http://schema.org","@type":"WebSite","name":"欢迎来到我的个人博客~","url":"http://8.219.11.28/","keywords":null,"description":"这些技术大部分是自己总结的，非官方","author":{"@type":"Person","name":"天明","image":{"@type":"ImageObject","url":"https://unpkg.com/volantis-static@0.0.1654736714924/media/org.volantis/blog/favicon/android-chrome-192x192.png"},"url":"http://8.219.11.28/","description":"这些技术大部分是自己总结的，非官方"},"publisher":{"@type":"Organization","name":"欢迎来到我的个人博客~","url":"http://8.219.11.28/","logo":{"@type":"ImageObject","url":"https://unpkg.com/volantis-static@0.0.1654736714924/media/org.volantis/blog/favicon/android-chrome-192x192.png","width":192,"height":192}},"potentialAction":{"@type":"SearchAction","name":"Site Search","target":{"@type":"EntryPoint","urlTemplate":"http://8.219.11.28?s={search_term_string}"},"query-input":"required name=search_term_string"}},{"@context":"http://schema.org","@type":"BlogPosting","description":"这些技术大部分是自己总结的，非官方","inLanguage":"en","mainEntityOfPage":{"@type":"WebPage","@id":"http://8.219.11.28/2024/02/23/%E5%89%8D%E5%90%8E%E7%AB%AF-SpringBoot/"},"author":{"@type":"Person","name":"天明","image":{"@type":"ImageObject","url":"https://unpkg.com/volantis-static@0.0.1654736714924/media/org.volantis/blog/favicon/android-chrome-192x192.png"},"url":"http://8.219.11.28/"},"publisher":{"@type":"Organization","name":"欢迎来到我的个人博客~","logo":{"@type":"ImageObject","url":"https://unpkg.com/volantis-static@0.0.1654736714924/media/org.volantis/blog/favicon/android-chrome-192x192.png","width":192,"height":192}},"url":"http://8.219.11.28/2024/02/23/%E5%89%8D%E5%90%8E%E7%AB%AF-SpringBoot/","wordCount":0,"datePublished":"2024-02-23T14:27:45.483Z","dateModified":"2024-02-17T04:39:33.886Z","image":{"@type":"ImageObject","url":"https://unpkg.com/volantis-static@0.0.1654736714924/media/org.volantis/blog/favicon/android-chrome-192x192.png","width":192,"height":192}}]</script>



      
        <!--
  pjax重载区域接口：
  1.  <pjax></pjax> 标签 pjax 标签必须存在于所有页面 否则 pjax error
  2.  script[data-pjax]
  3.  .pjax-reload script
  4.  .pjax
-->



<script src="https://unpkg.com/volantis-static@0.0.1654736714924/libs/pjax/pjax.min.js"></script>


<script>
    var pjax;
    document.addEventListener('DOMContentLoaded', function () {
      pjax = new Pjax({
        elements: 'a[href]:not([href^="#"]):not([href="javascript:void(0)"]):not([pjax-fancybox]):not([onclick="return false;"]):not([onclick="return!1"]):not([target="_blank"]):not([target="view_window"]):not([href$=".xml"])',
        selectors: [
          "head title",
          "head meta[name=keywords]",
          "head meta[name=description]",
          
          "#l_main",
          "#pjax-header-nav-list",
          ".pjax",
          "pjax", // <pjax></pjax> 标签
          "script[data-pjax], .pjax-reload script" // script标签添加data-pjax 或 script标签外层添加.pjax-reload 的script代码段重载
        ],
        cacheBust: false,   // url 地址追加时间戳，用以避免浏览器缓存
        timeout: 5000,
        
      });
    });

    document.addEventListener('pjax:send', function (e) {
      //window.stop(); // 相当于点击了浏览器的停止按钮

      try {
        var currentUrl = window.location.pathname;
        var targetUrl = e.triggerElement.href;
        var banUrl = [""];
        if (banUrl[0] != "") {
          banUrl.forEach(item => {
            if(currentUrl.indexOf(item) != -1 || targetUrl.indexOf(item) != -1) {
              window.location.href = targetUrl;
            }
          });
        }
      } catch (error) {}

      // 使用 volantis.pjax.send 方法传入pjax:send回调函数 参见layout/_partial/scripts/global.ejs
      volantis.pjax.method.send.start();
    });

    document.addEventListener('pjax:complete', function () {
      // 使用 volantis.pjax.push 方法传入重载函数 参见layout/_partial/scripts/global.ejs
      volantis.pjax.method.complete.start();
    });

    document.addEventListener('pjax:error', function (e) {
      if(volantis.debug) {
        console.error(e);
        console.log('pjax error: \n' + JSON.stringify(e));
      }else{
        // 使用 volantis.pjax.error 方法传入pjax:error回调函数 参见layout/_partial/scripts/global.ejs
        volantis.pjax.method.error.start();
        window.location.href = e.triggerElement.href;
      }
    });
</script>

      
    </div>
    <!-- import body_end begin-->
    <!-- import body_end end-->
    <!-- Custom Files bodyEnd begin-->
    
    <!-- Custom Files bodyEnd end-->
    <!-- front-matter body_end begin -->
    <!-- front-matter body_end end -->
  </body>
</html>
